diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index 3c46d611702118f7d72e366ca884a6a3c1601266..072089ac51f1442ab2f4d28410e4c4e10615f3f9 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -7,6 +7,7 @@ graft third_party/zlib
 include src/python/grpcio/commands.py
 include src/python/grpcio/grpc_version.py
 include src/python/grpcio/grpc_core_dependencies.py
+include src/python/grpcio/precompiled.py
 include src/python/grpcio/support.py
 include src/python/grpcio/README.rst
 include requirements.txt
diff --git a/setup.py b/setup.py
index 7da070ef0f50f8eed863fc5f64528907c7c66994..135c818885092f152a338d416e0f5a72acac0e3d 100644
--- a/setup.py
+++ b/setup.py
@@ -53,6 +53,7 @@ sys.path.insert(0, os.path.abspath(PYTHON_STEM))
 
 # Break import-style to ensure we can actually find our in-repo dependencies.
 import commands
+import precompiled
 import grpc_core_dependencies
 import grpc_version
 
@@ -156,15 +157,14 @@ SETUP_REQUIRES = (
 ) + INSTALL_REQUIRES
 
 COMMAND_CLASS = {
-    'install': commands.Install,
     'doc': commands.SphinxDocumentation,
     'build_proto_modules': commands.BuildProtoModules,
     'build_project_metadata': commands.BuildProjectMetadata,
     'build_py': commands.BuildPy,
     'build_ext': commands.BuildExt,
+    'build_tagged_ext': precompiled.BuildTaggedExt,
     'gather': commands.Gather,
     'run_interop': commands.RunInterop,
-    'bdist_wheel_grpc_custom': commands.BdistWheelCustomName,
 }
 
 # Ensure that package data is copied over before any commands have been run:
@@ -205,9 +205,12 @@ PACKAGE_DATA = {
     'grpc._adapter': [
         'credentials/roots.pem'
     ],
+    # Binaries that may or may not be present in the final installation, but are
+    # mentioned here for completeness.
     'grpc._cython': [
         '_windows/grpc_c.32.python',
         '_windows/grpc_c.64.python',
+        'cygrpc.so',
     ],
 }
 if INSTALL_TESTS:
@@ -217,19 +220,22 @@ else:
   PACKAGES = setuptools.find_packages(
       PYTHON_STEM, exclude=['tests', 'tests.*'])
 
-setuptools.setup(
-    name='grpcio',
-    version=grpc_version.VERSION,
-    license=LICENSE,
-    ext_modules=CYTHON_EXTENSION_MODULES,
-    packages=list(PACKAGES),
-    package_dir=PACKAGE_DIRECTORIES,
-    package_data=PACKAGE_DATA,
-    install_requires=INSTALL_REQUIRES,
-    setup_requires=SETUP_REQUIRES,
-    cmdclass=COMMAND_CLASS,
-    tests_require=TESTS_REQUIRE,
-    test_suite=TEST_SUITE,
-    test_loader=TEST_LOADER,
-    test_runner=TEST_RUNNER,
-)
+setup_arguments = {
+    'name': 'grpcio',
+    'version': grpc_version.VERSION,
+    'license': LICENSE,
+    'ext_modules': CYTHON_EXTENSION_MODULES,
+    'packages': list(PACKAGES),
+    'package_dir': PACKAGE_DIRECTORIES,
+    'package_data': PACKAGE_DATA,
+    'install_requires': INSTALL_REQUIRES,
+    'setup_requires': SETUP_REQUIRES,
+    'cmdclass': COMMAND_CLASS,
+    'tests_require': TESTS_REQUIRE,
+    'test_loader': TEST_LOADER,
+    'test_runner': TEST_RUNNER,
+}
+
+precompiled.update_setup_arguments(setup_arguments)
+
+setuptools.setup(**setup_arguments)
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 58af6bebf56f754fce72ca93e659a02eb5f127fc..aa29c728f259e6e47e2689e8978fd07b6bea7213 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -46,21 +46,11 @@ from setuptools.command import build_py
 from setuptools.command import easy_install
 from setuptools.command import install
 from setuptools.command import test
-from wheel import bdist_wheel
 
 import support
 
 PYTHON_STEM = os.path.dirname(os.path.abspath(__file__))
 
-BINARIES_REPOSITORY = os.environ.get(
-    'GRPC_PYTHON_BINARIES_REPOSITORY',
-    'https://storage.googleapis.com/grpc-precompiled-binaries/python')
-
-USE_GRPC_CUSTOM_BDIST = bool(int(os.environ.get(
-    'GRPC_PYTHON_USE_CUSTOM_BDIST', '1')))
-
-GRPC_CUSTOM_BDIST_EXT = '.whl'
-
 CONF_PY_ADDENDUM = """
 extensions.append('sphinx.ext.napoleon')
 napoleon_google_docstring = True
@@ -111,98 +101,6 @@ def _get_grpc_custom_bdist(decorated_basename, target_bdist_basename):
   return bdist_path
 
 
-class WheelNameMixin(object):
-  """Mixin for setuptools.Command classes to enable acquiring the bdist name."""
-
-  def wheel_custom_name(self):
-    base = self.wheel_name()
-    # Drop troublesome parts of the target tuple
-    base_split = base.split('-')
-    base = '-'.join(base_split[0:3] + base_split[4:])
-    flavor = 'ucs2' if sys.maxunicode == 65535 else 'ucs4'
-    return '{base}-{flavor}'.format(base=base, flavor=flavor)
-
-  def wheel_name(self):
-    wheel_command = self.get_finalized_command('bdist_wheel')
-    return wheel_command.get_archive_basename()
-
-
-class Install(install.install, WheelNameMixin):
-  """Custom Install command for gRPC Python.
-
-  This is for bdist shims and whatever else we might need a custom install
-  command for.
-  """
-
-  user_options = install.install.user_options + [
-      # TODO(atash): remove this once PyPI has better Linux bdist support. See
-      # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
-      ('use-grpc-custom-bdist', None,
-       'Whether to retrieve a binary from the gRPC binary repository instead '
-       'of building from source.'),
-  ]
-
-  def initialize_options(self):
-    install.install.initialize_options(self)
-    self.use_grpc_custom_bdist = USE_GRPC_CUSTOM_BDIST
-
-  def finalize_options(self):
-    install.install.finalize_options(self)
-
-  def run(self):
-    if self.use_grpc_custom_bdist:
-      try:
-        try:
-          bdist_path = _get_grpc_custom_bdist(self.wheel_custom_name(),
-                                              self.wheel_name())
-        except CommandError as error:
-          sys.stderr.write(
-              '\nWARNING: Failed to acquire grpcio prebuilt binary:\n'
-              '{}.\n\n'.format(error.message))
-          raise
-        try:
-          self._run_bdist_retrieval_install(bdist_path)
-        except Exception as error:
-          # if anything else happens (and given how there's no way to really know
-          # what's happening in setuptools here, I mean *anything*), warn the user
-          # and fall back to building from source.
-          sys.stderr.write(
-              '{}\nWARNING: Failed to install grpcio prebuilt binary.\n\n'
-                  .format(traceback.format_exc()))
-          raise
-      except Exception:
-        install.install.run(self)
-    else:
-      install.install.run(self)
-
-  # TODO(atash): Remove this once PyPI has better Linux bdist support. See
-  # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
-  def _run_bdist_retrieval_install(self, bdist_path):
-    import pip
-    pip.main(['install', bdist_path])
-
-
-class BdistWheelCustomName(bdist_wheel.bdist_wheel, WheelNameMixin):
-  """Thin wrapper around the bdist command to build with our custom name."""
-
-  description = ("Create a gRPC custom-named wheel distribution. "
-                 "Cannot be run with any other distribution-related command.")
-
-  def run(self):
-    # TODO(atash): if the hack we use to support Linux binaries becomes
-    # 'supported' (i.e.
-    # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
-    # is not solved and we see users beginning to use this command, ill-advised
-    # as that may be) consider making the following capable of running with
-    # other distribution-related commands. Currently it depends on the (AFAIK
-    # undocumented, private) ordering of the distribution files.
-    bdist_wheel.bdist_wheel.run(self)
-    output = self.distribution.dist_files[-1][2]
-    target = os.path.join(
-        self.dist_dir, '{}.whl'.format(self.wheel_custom_name()))
-    shutil.move(output, target)
-
-
 class SphinxDocumentation(setuptools.Command):
   """Command to generate documentation via sphinx."""
 
diff --git a/src/python/grpcio/precompiled.py b/src/python/grpcio/precompiled.py
new file mode 100644
index 0000000000000000000000000000000000000000..05c651b506f9b5785a9125a77420eb733a8cf9a3
--- /dev/null
+++ b/src/python/grpcio/precompiled.py
@@ -0,0 +1,102 @@
+# Copyright 2015-2016, 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.
+
+import os
+import platform
+import shutil
+import sys
+
+import setuptools
+
+import commands
+import grpc_version
+
+try:
+  from urllib2 import urlopen
+except ImportError:
+  from urllib.request import urlopen
+
+PYTHON_STEM = os.path.dirname(os.path.abspath(__file__))
+BINARIES_REPOSITORY = os.environ.get(
+    'GRPC_PYTHON_BINARIES_REPOSITORY',
+    'https://storage.googleapis.com/grpc-precompiled-binaries/python')
+USE_PRECOMPILED_BINARIES = bool(int(os.environ.get(
+    'GRPC_PYTHON_USE_PRECOMPILED_BINARIES', '1')))
+
+def _tagged_ext_name(base):
+  uname = platform.uname()
+  tags = '-'.join((grpc_version.VERSION, uname[0], uname[4]))
+  flavor = 'ucs2' if sys.maxunicode == 65535 else 'ucs4'
+  return '{base}-{tags}-{flavor}'.format(base=base, tags=tags, flavor=flavor)
+
+
+class BuildTaggedExt(setuptools.Command):
+
+  description = 'build the gRPC tagged extensions'
+  user_options = []
+
+  def initialize_options(self):
+    # distutils requires this override.
+    pass
+
+  def finalize_options(self):
+    # distutils requires this override.
+    pass
+
+  def run(self):
+    if 'linux' in sys.platform:
+      self.run_command('build_ext')
+      try:
+        os.makedirs('dist/')
+      except OSError:
+        pass
+      shutil.copyfile(
+          os.path.join(PYTHON_STEM, 'grpc/_cython/cygrpc.so'),
+          'dist/{}.so'.format(_tagged_ext_name('cygrpc')))
+    else:
+      sys.stderr.write('nothing to do for build_tagged_ext\n')
+
+
+def update_setup_arguments(setup_arguments):
+  url = '{}/{}.so'.format(BINARIES_REPOSITORY, _tagged_ext_name('cygrpc'))
+  target_path = os.path.join(PYTHON_STEM, 'grpc/_cython/cygrpc.so')
+  try:
+    extension = urlopen(url).read()
+  except:
+    sys.stderr.write(
+        'could not download precompiled extension: {}\n'.format(url))
+    return
+  try:
+    with open(target_path, 'w') as target:
+      target.write(extension)
+    setup_arguments['ext_modules'] = []
+  except:
+    sys.stderr.write(
+        'could not write precompiled extension to directory: {} -> {}\n'
+            .format(url, target_path))
diff --git a/tools/run_tests/build_artifact_python.sh b/tools/run_tests/build_artifact_python.sh
index 5768485ca2a798b26f61fdbd47cc7d01d6754922..6e7ab911d5bb5215fe0eccc9ebfd0a23a18bf774 100755
--- a/tools/run_tests/build_artifact_python.sh
+++ b/tools/run_tests/build_artifact_python.sh
@@ -46,7 +46,7 @@ fi
 GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
 GRPC_PYTHON_BUILD_WITH_CYTHON=1 \
 ${SETARCH_CMD} python setup.py  \
-    bdist_wheel_grpc_custom
+    build_tagged_ext
 
 GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
 GRPC_PYTHON_BUILD_WITH_CYTHON=1 \