diff --git a/BUILD b/BUILD
index e01313f35dbbc37593b638b7889cd0684b2e753d..49c340d070c07baf7f56124677470dbecd830d2f 100644
--- a/BUILD
+++ b/BUILD
@@ -1411,32 +1411,46 @@ grpc_cc_library(
     ],
 )
 
+grpc_cc_library(
+    name = "tsi_interface",
+    srcs = [
+        "src/core/tsi/transport_security.c",
+        "src/core/tsi/transport_security_adapter.c",
+    ],
+    hdrs = [
+        "src/core/tsi/transport_security.h",
+        "src/core/tsi/transport_security_adapter.h",
+        "src/core/tsi/transport_security_interface.h",
+    ],
+    language = "c",
+    deps = [
+        "gpr",
+        "grpc_trace",
+    ],
+)
+
 grpc_cc_library(
     name = "tsi",
     srcs = [
         "src/core/tsi/fake_transport_security.c",
         "src/core/tsi/gts_transport_security.c",
         "src/core/tsi/ssl_transport_security.c",
-        "src/core/tsi/transport_security.c",
-        "src/core/tsi/transport_security_adapter.c",
+        "src/core/tsi/transport_security_grpc.c",
     ],
     hdrs = [
         "src/core/tsi/fake_transport_security.h",
         "src/core/tsi/gts_transport_security.h",
         "src/core/tsi/ssl_transport_security.h",
         "src/core/tsi/ssl_types.h",
-        "src/core/tsi/transport_security.h",
-        "src/core/tsi/transport_security_adapter.h",
-        "src/core/tsi/transport_security_interface.h",
+        "src/core/tsi/transport_security_grpc.h",
     ],
     external_deps = [
         "libssl",
     ],
     language = "c",
     deps = [
-        "gpr",
         "grpc_base",
-        "grpc_trace",
+        "tsi_interface",
     ],
 )
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 743b34f11ae1433cb200494c9a97ca5cacd49cae..8dc4758d238acef1920a1f18063a2cea2da31ef4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1132,6 +1132,7 @@ add_library(grpc
   src/core/tsi/fake_transport_security.c
   src/core/tsi/gts_transport_security.c
   src/core/tsi/ssl_transport_security.c
+  src/core/tsi/transport_security_grpc.c
   src/core/tsi/transport_security.c
   src/core/tsi/transport_security_adapter.c
   src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -1503,6 +1504,7 @@ add_library(grpc_cronet
   src/core/tsi/fake_transport_security.c
   src/core/tsi/gts_transport_security.c
   src/core/tsi/ssl_transport_security.c
+  src/core/tsi/transport_security_grpc.c
   src/core/tsi/transport_security.c
   src/core/tsi/transport_security_adapter.c
   src/core/ext/transport/chttp2/client/chttp2_connector.c
diff --git a/Makefile b/Makefile
index af0ca3f1262d884041052eb66257d509ae9fae41..74f05f592dce4c99d8f40b5c7d39648d2490f115 100644
--- a/Makefile
+++ b/Makefile
@@ -3079,6 +3079,7 @@ LIBGRPC_SRC = \
     src/core/tsi/fake_transport_security.c \
     src/core/tsi/gts_transport_security.c \
     src/core/tsi/ssl_transport_security.c \
+    src/core/tsi/transport_security_grpc.c \
     src/core/tsi/transport_security.c \
     src/core/tsi/transport_security_adapter.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
@@ -3448,6 +3449,7 @@ LIBGRPC_CRONET_SRC = \
     src/core/tsi/fake_transport_security.c \
     src/core/tsi/gts_transport_security.c \
     src/core/tsi/ssl_transport_security.c \
+    src/core/tsi/transport_security_grpc.c \
     src/core/tsi/transport_security.c \
     src/core/tsi/transport_security_adapter.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
@@ -19721,6 +19723,7 @@ src/core/tsi/gts_transport_security.c: $(OPENSSL_DEP)
 src/core/tsi/ssl_transport_security.c: $(OPENSSL_DEP)
 src/core/tsi/transport_security.c: $(OPENSSL_DEP)
 src/core/tsi/transport_security_adapter.c: $(OPENSSL_DEP)
+src/core/tsi/transport_security_grpc.c: $(OPENSSL_DEP)
 src/cpp/client/cronet_credentials.cc: $(OPENSSL_DEP)
 src/cpp/client/secure_credentials.cc: $(OPENSSL_DEP)
 src/cpp/common/auth_property_iterator.cc: $(OPENSSL_DEP)
diff --git a/binding.gyp b/binding.gyp
index 2ca36e8f69d7ce2f102e2fdeee7f63341d48f07c..bbefd05c20bc932b05a5370f27f0b1d65079700b 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -841,6 +841,7 @@
         'src/core/tsi/fake_transport_security.c',
         'src/core/tsi/gts_transport_security.c',
         'src/core/tsi/ssl_transport_security.c',
+        'src/core/tsi/transport_security_grpc.c',
         'src/core/tsi/transport_security.c',
         'src/core/tsi/transport_security_adapter.c',
         'src/core/ext/transport/chttp2/server/chttp2_server.c',
diff --git a/build.yaml b/build.yaml
index f57119a87cc0f5def01a6cb1fcbd96c874869ecc..14d49cc7a4e614b2ea3671e42d276ca97288bc8d 100644
--- a/build.yaml
+++ b/build.yaml
@@ -925,15 +925,12 @@ filegroups:
   - src/core/tsi/gts_transport_security.h
   - src/core/tsi/ssl_transport_security.h
   - src/core/tsi/ssl_types.h
-  - src/core/tsi/transport_security.h
-  - src/core/tsi/transport_security_adapter.h
-  - src/core/tsi/transport_security_interface.h
+  - src/core/tsi/transport_security_grpc.h
   src:
   - src/core/tsi/fake_transport_security.c
   - src/core/tsi/gts_transport_security.c
   - src/core/tsi/ssl_transport_security.c
-  - src/core/tsi/transport_security.c
-  - src/core/tsi/transport_security_adapter.c
+  - src/core/tsi/transport_security_grpc.c
   deps:
   - gpr
   plugin: grpc_tsi_gts
@@ -941,6 +938,20 @@ filegroups:
   uses:
   - grpc_trace
   - grpc_base
+  - tsi_interface
+- name: tsi_interface
+  headers:
+  - src/core/tsi/transport_security.h
+  - src/core/tsi/transport_security_adapter.h
+  - src/core/tsi/transport_security_interface.h
+  src:
+  - src/core/tsi/transport_security.c
+  - src/core/tsi/transport_security_adapter.c
+  deps:
+  - gpr
+  secure: true
+  uses:
+  - grpc_trace
 - name: grpc++_codegen_base
   language: c++
   public_headers:
diff --git a/config.m4 b/config.m4
index 18671331393638c3b72909d5f0335f767c3d9bba..f6f8531b2fd1b319eea70da9444842fce3ac7972 100644
--- a/config.m4
+++ b/config.m4
@@ -270,6 +270,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/tsi/fake_transport_security.c \
     src/core/tsi/gts_transport_security.c \
     src/core/tsi/ssl_transport_security.c \
+    src/core/tsi/transport_security_grpc.c \
     src/core/tsi/transport_security.c \
     src/core/tsi/transport_security_adapter.c \
     src/core/ext/transport/chttp2/server/chttp2_server.c \
diff --git a/config.w32 b/config.w32
index 03e83b09e83ef446a9d801e82b7fe1ef8076138f..1d1a0a4b63f9c3cc65f7dedaf07f56fb11ca36bb 100644
--- a/config.w32
+++ b/config.w32
@@ -247,6 +247,7 @@ if (PHP_GRPC != "no") {
     "src\\core\\tsi\\fake_transport_security.c " +
     "src\\core\\tsi\\gts_transport_security.c " +
     "src\\core\\tsi\\ssl_transport_security.c " +
+    "src\\core\\tsi\\transport_security_grpc.c " +
     "src\\core\\tsi\\transport_security.c " +
     "src\\core\\tsi\\transport_security_adapter.c " +
     "src\\core\\ext\\transport\\chttp2\\server\\chttp2_server.c " +
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index dfd991b1c6018b7688affbdb2f3c6785a717d554..4b1a8f38a341814d02d2d9daa75fe1bd0a1b866e 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -290,6 +290,7 @@ Pod::Spec.new do |s|
                       'src/core/tsi/gts_transport_security.h',
                       'src/core/tsi/ssl_transport_security.h',
                       'src/core/tsi/ssl_types.h',
+                      'src/core/tsi/transport_security_grpc.h',
                       'src/core/tsi/transport_security.h',
                       'src/core/tsi/transport_security_adapter.h',
                       'src/core/tsi/transport_security_interface.h',
@@ -648,6 +649,7 @@ Pod::Spec.new do |s|
                       'src/core/tsi/fake_transport_security.c',
                       'src/core/tsi/gts_transport_security.c',
                       'src/core/tsi/ssl_transport_security.c',
+                      'src/core/tsi/transport_security_grpc.c',
                       'src/core/tsi/transport_security.c',
                       'src/core/tsi/transport_security_adapter.c',
                       'src/core/ext/transport/chttp2/server/chttp2_server.c',
@@ -782,6 +784,7 @@ Pod::Spec.new do |s|
                               'src/core/tsi/gts_transport_security.h',
                               'src/core/tsi/ssl_transport_security.h',
                               'src/core/tsi/ssl_types.h',
+                              'src/core/tsi/transport_security_grpc.h',
                               'src/core/tsi/transport_security.h',
                               'src/core/tsi/transport_security_adapter.h',
                               'src/core/tsi/transport_security_interface.h',
diff --git a/grpc.gemspec b/grpc.gemspec
old mode 100755
new mode 100644
index 07ca5de73c1825362d3ccae29a7ac3bc135b3ccc..f04a14167b19ee5bb8f64fb4f0d77a66874bf8f7
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -222,6 +222,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/tsi/gts_transport_security.h )
   s.files += %w( src/core/tsi/ssl_transport_security.h )
   s.files += %w( src/core/tsi/ssl_types.h )
+  s.files += %w( src/core/tsi/transport_security_grpc.h )
   s.files += %w( src/core/tsi/transport_security.h )
   s.files += %w( src/core/tsi/transport_security_adapter.h )
   s.files += %w( src/core/tsi/transport_security_interface.h )
@@ -580,6 +581,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/tsi/fake_transport_security.c )
   s.files += %w( src/core/tsi/gts_transport_security.c )
   s.files += %w( src/core/tsi/ssl_transport_security.c )
+  s.files += %w( src/core/tsi/transport_security_grpc.c )
   s.files += %w( src/core/tsi/transport_security.c )
   s.files += %w( src/core/tsi/transport_security_adapter.c )
   s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.c )
diff --git a/package.xml b/package.xml
index 9d3fb1b5de94305ab88b759484749cf5060f93d2..4e288b3c682bdb69b0a554f6dfba8a750ec821b8 100644
--- a/package.xml
+++ b/package.xml
@@ -236,6 +236,7 @@
     <file baseinstalldir="/" name="src/core/tsi/gts_transport_security.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/ssl_types.h" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/transport_security_grpc.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_adapter.h" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_interface.h" role="src" />
@@ -594,6 +595,7 @@
     <file baseinstalldir="/" name="src/core/tsi/fake_transport_security.c" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/gts_transport_security.c" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/ssl_transport_security.c" role="src" />
+    <file baseinstalldir="/" name="src/core/tsi/transport_security_grpc.c" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security.c" role="src" />
     <file baseinstalldir="/" name="src/core/tsi/transport_security_adapter.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.c" role="src" />
diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
index 810447313c5c30643d16f5af22808c61720d45a3..de16b356b62389e68e8fd4abe49e3941b2403ca5 100644
--- a/src/core/tsi/fake_transport_security.c
+++ b/src/core/tsi/fake_transport_security.c
@@ -407,8 +407,10 @@ static void fake_handshaker_result_destroy(tsi_handshaker_result *self) {
 
 static const tsi_handshaker_result_vtable handshaker_result_vtable = {
     fake_handshaker_result_extract_peer,
+    NULL, /* create_zero_copy_grpc_protector */
     fake_handshaker_result_create_frame_protector,
-    fake_handshaker_result_get_unused_bytes, fake_handshaker_result_destroy,
+    fake_handshaker_result_get_unused_bytes,
+    fake_handshaker_result_destroy,
 };
 
 static tsi_result fake_handshaker_result_create(
diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c
index 2b1f4310c14d79fd704d807e979bfcba98aaa23d..3637f3c190994d2d5f72d848e7f6dcfe9946d0ca 100644
--- a/src/core/tsi/transport_security.c
+++ b/src/core/tsi/transport_security.c
@@ -74,14 +74,12 @@ tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
                                        size_t *unprotected_bytes_size,
                                        unsigned char *protected_output_frames,
                                        size_t *protected_output_frames_size) {
-  if (self == NULL || unprotected_bytes == NULL ||
+  if (self == NULL || self->vtable == NULL || unprotected_bytes == NULL ||
       unprotected_bytes_size == NULL || protected_output_frames == NULL ||
       protected_output_frames_size == NULL) {
     return TSI_INVALID_ARGUMENT;
   }
-  if (self->vtable == NULL || self->vtable->protect == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->protect == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
                                protected_output_frames,
                                protected_output_frames_size);
@@ -90,13 +88,11 @@ tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
 tsi_result tsi_frame_protector_protect_flush(
     tsi_frame_protector *self, unsigned char *protected_output_frames,
     size_t *protected_output_frames_size, size_t *still_pending_size) {
-  if (self == NULL || protected_output_frames == NULL ||
+  if (self == NULL || self->vtable == NULL || protected_output_frames == NULL ||
       protected_output_frames_size == NULL || still_pending_size == NULL) {
     return TSI_INVALID_ARGUMENT;
   }
-  if (self->vtable == NULL || self->vtable->protect_flush == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->protect_flush == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->protect_flush(self, protected_output_frames,
                                      protected_output_frames_size,
                                      still_pending_size);
@@ -106,14 +102,12 @@ tsi_result tsi_frame_protector_unprotect(
     tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
     size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
     size_t *unprotected_bytes_size) {
-  if (self == NULL || protected_frames_bytes == NULL ||
+  if (self == NULL || self->vtable == NULL || protected_frames_bytes == NULL ||
       protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
       unprotected_bytes_size == NULL) {
     return TSI_INVALID_ARGUMENT;
   }
-  if (self->vtable == NULL || self->vtable->unprotect == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->unprotect == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->unprotect(self, protected_frames_bytes,
                                  protected_frames_bytes_size, unprotected_bytes,
                                  unprotected_bytes_size);
@@ -131,48 +125,44 @@ void tsi_frame_protector_destroy(tsi_frame_protector *self) {
 tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
                                                     unsigned char *bytes,
                                                     size_t *bytes_size) {
-  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+  if (self == NULL || self->vtable == NULL || bytes == NULL ||
+      bytes_size == NULL) {
     return TSI_INVALID_ARGUMENT;
   }
   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  if (self->vtable == NULL || self->vtable->get_bytes_to_send_to_peer == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->get_bytes_to_send_to_peer == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
 }
 
 tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
                                                   const unsigned char *bytes,
                                                   size_t *bytes_size) {
-  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+  if (self == NULL || self->vtable == NULL || bytes == NULL ||
+      bytes_size == NULL) {
     return TSI_INVALID_ARGUMENT;
   }
   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  if (self->vtable == NULL || self->vtable->process_bytes_from_peer == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->process_bytes_from_peer == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
 }
 
 tsi_result tsi_handshaker_get_result(tsi_handshaker *self) {
-  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self == NULL || self->vtable == NULL) return TSI_INVALID_ARGUMENT;
   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  if (self->vtable == NULL || self->vtable->get_result == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->get_result == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->get_result(self);
 }
 
 tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) {
-  if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
+  if (self == NULL || self->vtable == NULL || peer == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
   memset(peer, 0, sizeof(tsi_peer));
   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
   if (tsi_handshaker_get_result(self) != TSI_OK) {
     return TSI_FAILED_PRECONDITION;
   }
-  if (self->vtable == NULL || self->vtable->extract_peer == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->extract_peer == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->extract_peer(self, peer);
 }
 
@@ -180,14 +170,12 @@ tsi_result tsi_handshaker_create_frame_protector(
     tsi_handshaker *self, size_t *max_protected_frame_size,
     tsi_frame_protector **protector) {
   tsi_result result;
-  if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
-  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
-  if (tsi_handshaker_get_result(self) != TSI_OK) {
-    return TSI_FAILED_PRECONDITION;
-  }
-  if (self->vtable == NULL || self->vtable->create_frame_protector == NULL) {
-    return TSI_UNIMPLEMENTED;
+  if (self == NULL || self->vtable == NULL || protector == NULL) {
+    return TSI_INVALID_ARGUMENT;
   }
+  if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
+  if (tsi_handshaker_get_result(self) != TSI_OK) return TSI_FAILED_PRECONDITION;
+  if (self->vtable->create_frame_protector == NULL) return TSI_UNIMPLEMENTED;
   result = self->vtable->create_frame_protector(self, max_protected_frame_size,
                                                 protector);
   if (result == TSI_OK) {
@@ -201,11 +189,9 @@ tsi_result tsi_handshaker_next(
     size_t received_bytes_size, unsigned char **bytes_to_send,
     size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result,
     tsi_handshaker_on_next_done_cb cb, void *user_data) {
-  if (self == NULL) return TSI_INVALID_ARGUMENT;
+  if (self == NULL || self->vtable == NULL) return TSI_INVALID_ARGUMENT;
   if (self->handshaker_result_created) return TSI_FAILED_PRECONDITION;
-  if (self->vtable == NULL || self->vtable->next == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->next == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->next(self, received_bytes, received_bytes_size,
                             bytes_to_send, bytes_to_send_size,
                             handshaker_result, cb, user_data);
@@ -220,21 +206,21 @@ void tsi_handshaker_destroy(tsi_handshaker *self) {
 
 tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result *self,
                                               tsi_peer *peer) {
-  if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
-  memset(peer, 0, sizeof(tsi_peer));
-  if (self->vtable == NULL || self->vtable->extract_peer == NULL) {
-    return TSI_UNIMPLEMENTED;
+  if (self == NULL || self->vtable == NULL || peer == NULL) {
+    return TSI_INVALID_ARGUMENT;
   }
+  memset(peer, 0, sizeof(tsi_peer));
+  if (self->vtable->extract_peer == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->extract_peer(self, peer);
 }
 
 tsi_result tsi_handshaker_result_create_frame_protector(
     const tsi_handshaker_result *self, size_t *max_protected_frame_size,
     tsi_frame_protector **protector) {
-  if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
-  if (self->vtable == NULL || self->vtable->create_frame_protector == NULL) {
-    return TSI_UNIMPLEMENTED;
+  if (self == NULL || self->vtable == NULL || protector == NULL) {
+    return TSI_INVALID_ARGUMENT;
   }
+  if (self->vtable->create_frame_protector == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->create_frame_protector(self, max_protected_frame_size,
                                               protector);
 }
@@ -242,12 +228,11 @@ tsi_result tsi_handshaker_result_create_frame_protector(
 tsi_result tsi_handshaker_result_get_unused_bytes(
     const tsi_handshaker_result *self, const unsigned char **bytes,
     size_t *bytes_size) {
-  if (self == NULL || bytes == NULL || bytes_size == NULL) {
+  if (self == NULL || self->vtable == NULL || bytes == NULL ||
+      bytes_size == NULL) {
     return TSI_INVALID_ARGUMENT;
   }
-  if (self->vtable == NULL || self->vtable->get_unused_bytes == NULL) {
-    return TSI_UNIMPLEMENTED;
-  }
+  if (self->vtable->get_unused_bytes == NULL) return TSI_UNIMPLEMENTED;
   return self->vtable->get_unused_bytes(self, bytes, bytes_size);
 }
 
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
index 2c7db6bca920270be15860dd0a85f745985fe697..dde48a6b7f5ed70f63b2efe02ca0c3fe17008b2f 100644
--- a/src/core/tsi/transport_security.h
+++ b/src/core/tsi/transport_security.h
@@ -86,6 +86,10 @@ struct tsi_handshaker {
    See transport_security_interface.h for documentation. */
 typedef struct {
   tsi_result (*extract_peer)(const tsi_handshaker_result *self, tsi_peer *peer);
+  tsi_result (*create_zero_copy_grpc_protector)(
+      const tsi_handshaker_result *self,
+      size_t *max_output_protected_frame_size,
+      tsi_zero_copy_grpc_protector **protector);
   tsi_result (*create_frame_protector)(const tsi_handshaker_result *self,
                                        size_t *max_output_protected_frame_size,
                                        tsi_frame_protector **protector);
diff --git a/src/core/tsi/transport_security_adapter.c b/src/core/tsi/transport_security_adapter.c
index b6dc660c4756928017fea5a3e77d8b34f56eeb72..3b388af48ac514cb0d60ecf8940d6914c5536c4e 100644
--- a/src/core/tsi/transport_security_adapter.c
+++ b/src/core/tsi/transport_security_adapter.c
@@ -66,8 +66,11 @@ static void adapter_result_destroy(tsi_handshaker_result *self) {
 }
 
 static const tsi_handshaker_result_vtable result_vtable = {
-    adapter_result_extract_peer, adapter_result_create_frame_protector,
-    adapter_result_get_unused_bytes, adapter_result_destroy,
+    adapter_result_extract_peer,
+    NULL, /* create_zero_copy_grpc_protector */
+    adapter_result_create_frame_protector,
+    adapter_result_get_unused_bytes,
+    adapter_result_destroy,
 };
 
 /* Ownership of wrapped tsi_handshaker is transferred to the result object.  */
diff --git a/src/core/tsi/transport_security_grpc.c b/src/core/tsi/transport_security_grpc.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab2b6ddd541617642580177597d7e1b52fa88215
--- /dev/null
+++ b/src/core/tsi/transport_security_grpc.c
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/tsi/transport_security_grpc.h"
+
+/* This method creates a tsi_zero_copy_grpc_protector object.  */
+tsi_result tsi_handshaker_result_create_zero_copy_grpc_protector(
+    const tsi_handshaker_result *self, size_t *max_protected_frame_size,
+    tsi_zero_copy_grpc_protector **protector) {
+  if (self == NULL || self->vtable == NULL || protector == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->vtable->create_zero_copy_grpc_protector == NULL) {
+    return TSI_UNIMPLEMENTED;
+  }
+  return self->vtable->create_zero_copy_grpc_protector(
+      self, max_protected_frame_size, protector);
+}
+
+/* --- tsi_zero_copy_grpc_protector common implementation. ---
+
+   Calls specific implementation after state/input validation. */
+
+tsi_result tsi_zero_copy_grpc_protector_protect(
+    tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *unprotected_slices,
+    grpc_slice_buffer *protected_slices) {
+  if (self == NULL || self->vtable == NULL || unprotected_slices == NULL ||
+      protected_slices == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->vtable->protect == NULL) return TSI_UNIMPLEMENTED;
+  return self->vtable->protect(self, unprotected_slices, protected_slices);
+}
+
+tsi_result tsi_zero_copy_grpc_protector_unprotect(
+    tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *protected_slices,
+    grpc_slice_buffer *unprotected_slices) {
+  if (self == NULL || self->vtable == NULL || protected_slices == NULL ||
+      unprotected_slices == NULL) {
+    return TSI_INVALID_ARGUMENT;
+  }
+  if (self->vtable->unprotect == NULL) return TSI_UNIMPLEMENTED;
+  return self->vtable->unprotect(self, protected_slices, unprotected_slices);
+}
+
+void tsi_zero_copy_grpc_protector_destroy(tsi_zero_copy_grpc_protector *self) {
+  if (self == NULL) return;
+  self->vtable->destroy(self);
+}
diff --git a/src/core/tsi/transport_security_grpc.h b/src/core/tsi/transport_security_grpc.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ab5297cc487d4a5101df60af974b76d9f96ac3f
--- /dev/null
+++ b/src/core/tsi/transport_security_grpc.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H
+#define GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H
+
+#include <grpc/slice_buffer.h>
+#include "src/core/tsi/transport_security.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This method creates a tsi_zero_copy_grpc_protector object. It return TSI_OK
+   assuming there is no fatal error.
+   The caller is responsible for destroying the protector.  */
+tsi_result tsi_handshaker_result_create_zero_copy_grpc_protector(
+    const tsi_handshaker_result *self, size_t *max_output_protected_frame_size,
+    tsi_zero_copy_grpc_protector **protector);
+
+/* -- tsi_zero_copy_grpc_protector object --  */
+
+/* Outputs protected frames.
+   - unprotected_slices is the unprotected data to be protected.
+   - protected_slices is the protected output frames. One or more frames
+     may be produced in this protect function.
+   - This method returns TSI_OK in case of success or a specific error code in
+     case of failure.  */
+tsi_result tsi_zero_copy_grpc_protector_protect(
+    tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *unprotected_slices,
+    grpc_slice_buffer *protected_slices);
+
+/* Outputs unprotected bytes.
+   - protected_slices is the bytes of protected frames.
+   - unprotected_slices is the unprotected output data.
+   - This method returns TSI_OK in case of success. Success includes cases where
+     there is not enough data to output in which case unprotected_slices has 0
+     bytes.  */
+tsi_result tsi_zero_copy_grpc_protector_unprotect(
+    tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *protected_slices,
+    grpc_slice_buffer *unprotected_slices);
+
+/* Destroys the tsi_zero_copy_grpc_protector object.  */
+void tsi_zero_copy_grpc_protector_destroy(tsi_zero_copy_grpc_protector *self);
+
+/* Base for tsi_zero_copy_grpc_protector implementations.  */
+typedef struct {
+  tsi_result (*protect)(tsi_zero_copy_grpc_protector *self,
+                        grpc_slice_buffer *unprotected_slices,
+                        grpc_slice_buffer *protected_slices);
+  tsi_result (*unprotect)(tsi_zero_copy_grpc_protector *self,
+                          grpc_slice_buffer *protected_slices,
+                          grpc_slice_buffer *unprotected_slices);
+  void (*destroy)(tsi_zero_copy_grpc_protector *self);
+} tsi_zero_copy_grpc_protector_vtable;
+
+struct tsi_zero_copy_grpc_protector {
+  const tsi_zero_copy_grpc_protector_vtable *vtable;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H */
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
index 39ba8addc4985104bea4aee12252ce47e9f27d33..414c78603fe867e6e4c6a911045b59c736bd0e7f 100644
--- a/src/core/tsi/transport_security_interface.h
+++ b/src/core/tsi/transport_security_interface.h
@@ -62,6 +62,15 @@ const char *tsi_result_to_string(tsi_result result);
 
 extern grpc_tracer_flag tsi_tracing_enabled;
 
+/* -- tsi_zero_copy_grpc_protector object --
+
+  This object protects and unprotects grpc slice buffers with zero or minimized
+  memory copy once the handshake is done. Implementations of this object must be
+  thread compatible. This object depends on grpc and the details of this object
+  is defined in transport_security_grpc.h.  */
+
+typedef struct tsi_zero_copy_grpc_protector tsi_zero_copy_grpc_protector;
+
 /* --- tsi_frame_protector object ---
 
   This object protects and unprotects buffers once the handshake is done.
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index e52d43e81dc5a50b1391ba492d7410d8b228353c..dc4d28f95bd9143b26abddd8679a530742c2ab74 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -246,6 +246,7 @@ CORE_SOURCE_FILES = [
   'src/core/tsi/fake_transport_security.c',
   'src/core/tsi/gts_transport_security.c',
   'src/core/tsi/ssl_transport_security.c',
+  'src/core/tsi/transport_security_grpc.c',
   'src/core/tsi/transport_security.c',
   'src/core/tsi/transport_security_adapter.c',
   'src/core/ext/transport/chttp2/server/chttp2_server.c',
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index fd1a13563a1373ed55d0188ec586aa0fa4b5ffc6..4901fc92182542aafcd098eb422019f7a63a2584 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1421,6 +1421,8 @@ src/core/tsi/transport_security.c \
 src/core/tsi/transport_security.h \
 src/core/tsi/transport_security_adapter.c \
 src/core/tsi/transport_security_adapter.h \
+src/core/tsi/transport_security_grpc.c \
+src/core/tsi/transport_security_grpc.h \
 src/core/tsi/transport_security_interface.h \
 third_party/nanopb/pb_common.c \
 third_party/nanopb/pb_decode.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 41a299dd6298ceee10f4703457e98530c513b07f..30fef6fc0a53d27dd5818f45b442866b9f621ab3 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -9095,16 +9095,15 @@
     "deps": [
       "gpr", 
       "grpc_base", 
-      "grpc_trace"
+      "grpc_trace", 
+      "tsi_interface"
     ], 
     "headers": [
       "src/core/tsi/fake_transport_security.h", 
       "src/core/tsi/gts_transport_security.h", 
       "src/core/tsi/ssl_transport_security.h", 
       "src/core/tsi/ssl_types.h", 
-      "src/core/tsi/transport_security.h", 
-      "src/core/tsi/transport_security_adapter.h", 
-      "src/core/tsi/transport_security_interface.h"
+      "src/core/tsi/transport_security_grpc.h"
     ], 
     "is_filegroup": true, 
     "language": "c", 
@@ -9117,6 +9116,26 @@
       "src/core/tsi/ssl_transport_security.c", 
       "src/core/tsi/ssl_transport_security.h", 
       "src/core/tsi/ssl_types.h", 
+      "src/core/tsi/transport_security_grpc.c", 
+      "src/core/tsi/transport_security_grpc.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc_trace"
+    ], 
+    "headers": [
+      "src/core/tsi/transport_security.h", 
+      "src/core/tsi/transport_security_adapter.h", 
+      "src/core/tsi/transport_security_interface.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "tsi_interface", 
+    "src": [
       "src/core/tsi/transport_security.c", 
       "src/core/tsi/transport_security.h", 
       "src/core/tsi/transport_security_adapter.c", 
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 3b18b42ce9f0ecd70b05aa168ab8091722b999b4..8a659280a461593b258370bf570d6dcdcce1dc8b 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -347,6 +347,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\gts_transport_security.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_adapter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_interface.h" />
@@ -892,6 +893,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security_grpc.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security_adapter.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 546f8a57a85f40a638c08b217f9cb03a7bf31401..6879047f55b344b06d4ab669dddae9f7f2cccbc4 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -556,6 +556,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\tsi\ssl_transport_security.c">
       <Filter>src\core\tsi</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security_grpc.c">
+      <Filter>src\core\tsi</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\tsi\transport_security.c">
       <Filter>src\core\tsi</Filter>
     </ClCompile>
@@ -1010,6 +1013,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\ssl_types.h">
       <Filter>src\core\tsi</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security_grpc.h">
+      <Filter>src\core\tsi</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\tsi\transport_security.h">
       <Filter>src\core\tsi</Filter>
     </ClInclude>