diff --git a/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
index fdf44312ec31845d88f83301eb739153a8605684..93d26b559453a99c04bf74451654fc3bd5cd0848 100644
--- a/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/multilang_jessie_x64/Dockerfile.template
@@ -38,6 +38,10 @@
   <%include file="../../php_deps.include"/>
   <%include file="../../ruby_deps.include"/>
   <%include file="../../python_deps.include"/>
+  # Install coverage for Python test coverage reporting
+  RUN pip install coverage
+  ENV PATH ~/.local/bin:$PATH
+
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index 5d0c1686f18a8d6201be91eec66f6dca0bdb18cd..ea57d88c870883fa77f8a06cc1ba896e3cd807aa 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -135,6 +135,10 @@ RUN pip install pip --upgrade
 RUN pip install virtualenv
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
 
+# Install coverage for Python test coverage reporting
+RUN pip install coverage
+ENV PATH ~/.local/bin:$PATH
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/run_tests/helper_scripts/post_tests_php.sh b/tools/run_tests/helper_scripts/post_tests_php.sh
index 23dc202322fdb4d2d8927b4893342fbeb9e04068..43b665e23ee207650ebb5405fcadf0bc2226ee02 100755
--- a/tools/run_tests/helper_scripts/post_tests_php.sh
+++ b/tools/run_tests/helper_scripts/post_tests_php.sh
@@ -43,4 +43,4 @@ genhtml $tmp2 --output-directory $out
 rm $tmp2
 rm $tmp1
 
-cp -rv $root/src/php/coverage $root/reports/php
+# todo(mattkwong): generate coverage report for php and copy to reports/php
diff --git a/tools/run_tests/helper_scripts/post_tests_python.sh b/tools/run_tests/helper_scripts/post_tests_python.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4f5986b3a1a0ecf9a11dca6e15c846c40a303a55
--- /dev/null
+++ b/tools/run_tests/helper_scripts/post_tests_python.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+
+# change to directory of Python coverage files
+cd $(dirname $0)/../../../src/python/grpcio_tests/
+
+coverage combine .
+coverage html -i -d ./../../../reports/python
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 00dd4ca6056c64b43dd1c5393ab1bc17ff1a9fdd..0b4f26ca4401576d17fc9df89507f8725df42abf 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -614,7 +614,10 @@ class PythonLanguage(object):
     return [config.build for config in self.pythons]
 
   def post_tests_steps(self):
-    return []
+    if self.config != 'gcov':
+      return []
+    else:
+      return [['tools/run_tests/helper_scripts/post_tests_python.sh']]
 
   def makefile_name(self):
     return 'Makefile'
@@ -1270,7 +1273,9 @@ if any(language.make_options() for language in languages):
     print('languages with custom make options cannot be built simultaneously with other languages')
     sys.exit(1)
   else:
-    language_make_options = next(iter(languages)).make_options()
+    # Combining make options is not clean and just happens to work. It allows C/C++ and C# to build
+    # together, and is only used under gcov. All other configs should build languages individually.
+    language_make_options = list(set([make_option for lang in languages for make_option in lang.make_options()]))
 
 if args.use_docker:
   if not args.travis: