diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.h b/src/objective-c/GRPCClient/GRPCCall+Tests.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d617b05d99df786e451589adaf96bbc7a45b922
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCall+Tests.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2015, 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 "GRPCCall.h"
+
+@interface GRPCCall (Tests)
+
+// Establish all SSL connections to the provided host using the passed SSL target name and the root
+// certificates found in the file at |certsPath|.
+// Must be called before any gRPC call to that host is made.
++ (void)useTestCertsPath:(NSString *)certsPath
+                testName:(NSString *)testName
+                 forHost:(NSString *)host;
+
+@end
diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m
new file mode 100644
index 0000000000000000000000000000000000000000..7c5b81d661d756b9cbb654285a6145d0bf7608ba
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright 2015, 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 "GRPCCall+Tests.h"
+
+#import "private/GRPCHost.h"
+
+@implementation GRPCCall (Tests)
++ (void)useTestCertsPath:(NSString *)certsPath
+                testName:(NSString *)testName
+                 forHost:(NSString *)host {
+  GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
+  hostConfig.secure = YES;
+  hostConfig.pathToCertificates = certsPath;
+  hostConfig.hostNameOverride = testName;
+}
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 49f8b712b9d09aed061178d118342f6c006d97f8..fa9f6f28d1f541437dd540f3f86d7e991934448b 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -36,15 +36,9 @@
 #include <grpc/grpc.h>
 
 // Each separate instance of this class represents at least one TCP connection to the provided host.
-// To create a grpc_call to that host, use |unmanagedCallWithPath|. Release this object when the
-// call is finished.
+// Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|.
 @interface GRPCChannel : NSObject
+@property(nonatomic) grpc_channel *unmanagedChannel;
 
-// Convenience constructor to allow for reuse of connections.
-+ (instancetype)channelToHost:(NSString *)host;
-
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel
-                       hostName:(NSString *)hostName NS_DESIGNATED_INITIALIZER;
-
-- (grpc_call *)unmanagedCallWithPath:(NSString *)path;
+- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 90973cd83d09f9e082273672bcec9aa499a2838a..68a402db97a4865823b3ad02a926a996c8cbc968 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -33,85 +33,23 @@
 
 #import "GRPCChannel.h"
 
-#include <grpc/grpc.h>
-
-#import "GRPCCompletionQueue.h"
-#import "GRPCSecureChannel.h"
-#import "GRPCUnsecuredChannel.h"
-
-@implementation GRPCChannel {
-  grpc_channel *_unmanagedChannel;
-  NSString *_hostName;
-  GRPCCompletionQueue *_queue;
-}
-
-+ (instancetype)channelToHost:(NSString *)host {
-  // TODO(mlumish): Investigate whether a cache with strong links is a good idea
-  static NSMutableDictionary *channelCache;
-  static dispatch_once_t cacheInitialization;
-  dispatch_once(&cacheInitialization, ^{
-    channelCache = [NSMutableDictionary dictionary];
-  });
-  GRPCChannel *channel = channelCache[host];
-  if (!channel) {
-    channel = [self uncachedChannelToHost:host];
-    channelCache[host] = channel;
-  }
-  return channel;
-}
-
-+ (instancetype)uncachedChannelToHost:(NSString *)host {
-  if (![host rangeOfString:@"://"].length) {
-    // No scheme provided; assume https.
-    host = [@"https://" stringByAppendingString:host];
-  }
-  NSURL *hostURL = [NSURL URLWithString:host];
-  if (!hostURL) {
-    [NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", host];
-  }
-  if ([hostURL.scheme isEqualToString:@"https"]) {
-    host = [@[hostURL.host, hostURL.port ?: @443] componentsJoinedByString:@":"];
-    return [[GRPCSecureChannel alloc] initWithHost:host];
-  }
-  if ([hostURL.scheme isEqualToString:@"http"]) {
-    host = [@[hostURL.host, hostURL.port ?: @80] componentsJoinedByString:@":"];
-    return [[GRPCUnsecuredChannel alloc] initWithHost:host];
-  }
-  [NSException raise:NSInvalidArgumentException
-              format:@"URL scheme %@ isn't supported.", hostURL.scheme];
-  return nil; // silence warning.
-}
+@implementation GRPCChannel
 
 - (instancetype)init {
-  return [self initWithChannel:NULL hostName:nil];
+  return [self initWithChannel:NULL];
 }
 
-- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel
-                       hostName:(NSString *)hostName {
-  if (!unmanagedChannel || !hostName) {
-    [NSException raise:NSInvalidArgumentException
-                format:@"Neither unmanagedChannel nor hostName can be nil."];
+// Designated initializer
+- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
+  if (!unmanagedChannel) {
+    [NSException raise:NSInvalidArgumentException format:@"unmanagedChannel can't be nil."];
   }
   if ((self = [super init])) {
     _unmanagedChannel = unmanagedChannel;
-    _hostName = hostName;
-    // In case sharing the queue creates contention, we can change it to one per grpc_call.
-    _queue = [GRPCCompletionQueue completionQueue];
-    if (!_queue) {
-      return nil;
-    }
   }
   return self;
 }
 
-- (grpc_call *)unmanagedCallWithPath:(NSString *)path {
-  return grpc_channel_create_call(_unmanagedChannel,
-                                  _queue.unmanagedQueue,
-                                  path.UTF8String,
-                                  _hostName.UTF8String,
-                                  gpr_inf_future(GPR_CLOCK_REALTIME));
-}
-
 - (void)dealloc {
   // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
   // as in the past that made this call to crash.
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index 12535c961653cc85e34440ebf3d7fb71469fde5f..696069c200f503c8be40b49e193d488b5c56fec6 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -38,8 +38,6 @@
 @implementation GRPCCompletionQueue
 
 + (instancetype)completionQueue {
-  // TODO(jcanizales): Reuse completion queues to consume only one thread,
-  // instead of one per call.
   return [[self alloc] init];
 }
 
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
new file mode 100644
index 0000000000000000000000000000000000000000..86e43a283d7ea69ef08b24704bcb5e022ff6d675
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2015, 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 <Foundation/Foundation.h>
+
+#import "GRPCCompletionQueue.h"
+
+@interface GRPCHost : NSObject
+
+@property(nonatomic, readonly) NSString *address;
+
+// The following properties should only be modified for testing:
+
+@property(nonatomic, getter=isSecure) BOOL secure;
+
+@property(nonatomic, copy) NSString *pathToCertificates;
+@property(nonatomic, copy) NSString *hostNameOverride;
+
+// Host objects initialized with the same address are the same.
++ (instancetype)hostWithAddress:(NSString *)address;
+- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
+
+// Create a grpc_call object to the provided path on this host.
+- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue;
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
new file mode 100644
index 0000000000000000000000000000000000000000..405545b86bb0b787c375b288ff0266243d412aee
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright 2015, 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 "GRPCHost.h"
+
+#import "GRPCChannel.h"
+#import "GRPCSecureChannel.h"
+#import "GRPCUnsecuredChannel.h"
+
+@interface GRPCHost ()
+// TODO(mlumish): Investigate whether a caching channels with strong links is a good idea.
+@property(nonatomic, strong) GRPCChannel *channel;
+@end
+
+@implementation GRPCHost
+
++ (instancetype)hostWithAddress:(NSString *)address {
+  return [[self alloc] initWithAddress:address];
+}
+
+- (instancetype)init {
+  return [self initWithAddress:nil];
+}
+
+// Default initializer.
+- (instancetype)initWithAddress:(NSString *)address {
+
+  // Verify and normalize the address, and decide whether to use SSL.
+  if (![address rangeOfString:@"://"].length) {
+    // No scheme provided; assume https.
+    address = [@"https://" stringByAppendingString:address];
+  }
+  NSURL *hostURL = [NSURL URLWithString:address];
+  if (!hostURL) {
+    [NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", address];
+  }
+  NSString *scheme = hostURL.scheme;
+  if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
+    [NSException raise:NSInvalidArgumentException format:@"URL scheme %@ isn't supported.", scheme];
+  }
+  NSNumber *port = hostURL.port ?: [scheme isEqualToString:@"https"] ? @443 : @80;
+  address = [@[hostURL.host, port] componentsJoinedByString:@":"];
+
+  // Look up the GRPCHost in the cache.
+  // TODO(jcanizales): Make this cache thread-safe.
+  static NSMutableDictionary *hostCache;
+  static dispatch_once_t cacheInitialization;
+  dispatch_once(&cacheInitialization, ^{
+    hostCache = [NSMutableDictionary dictionary];
+  });
+  if (hostCache[address]) {
+    // We could verify here that the cached host uses the same protocol that we're expecting. But
+    // picking HTTP by adding the scheme to the address is going away (to make the use of insecure
+    // channels less subtle), so it's not worth it now.
+    return hostCache[address];
+  }
+
+  if ((self = [super init])) {
+    _address = address;
+    _secure = [scheme isEqualToString:@"https"];
+    hostCache[address] = self;
+  }
+  return self;
+}
+
+- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
+  if (!queue || !path) {
+    return NULL;
+  }
+  return grpc_channel_create_call(self.channel.unmanagedChannel,
+                                  queue.unmanagedQueue,
+                                  path.UTF8String,
+                                  self.hostName.UTF8String,
+                                  gpr_inf_future(GPR_CLOCK_REALTIME));
+}
+
+- (GRPCChannel *)channel {
+  // Create it lazily.
+  if (!_channel) {
+    if (_secure) {
+      _channel = [[GRPCSecureChannel alloc] initWithHost:_address
+                                      pathToCertificates:_pathToCertificates
+                                        hostNameOverride:_hostNameOverride];
+    } else {
+      _channel = [[GRPCUnsecuredChannel alloc] initWithHost:_address];
+    }
+  }
+  return _channel;
+}
+
+- (NSString *)hostName {
+  // TODO(jcanizales): Default to nil instead of _address when Issue #2635 is clarified.
+  return _hostNameOverride ?: _address;
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
index 8c5fe33d61e4618b01fafcbdeb3bfc92120a38a2..8b259c8dadaf3a5d0bfaf1bf736a6515d15ff14e 100644
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
@@ -31,8 +31,18 @@
  *
  */
 
+#import <grpc/grpc_security.h>
+
 #import "GRPCChannel.h"
 
 @interface GRPCSecureChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithHost:(NSString *)host;
+
+- (instancetype)initWithHost:(NSString *)host
+          pathToCertificates:(NSString *)path
+            hostNameOverride:(NSString *)hostNameOverride;
+
+- (instancetype)initWithHost:(NSString *)host
+                 credentials:(grpc_credentials *)credentials
+                        args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
index 2dbbd52087837b6e17373ea6cbc320ba9d612b31..c783462dd3056e26df887772784c33d162b33532 100644
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
@@ -33,12 +33,24 @@
 
 #import "GRPCSecureChannel.h"
 
-#import <grpc/grpc_security.h>
+grpc_credentials *CertificatesAtPath(NSString *path) {
+  NSData *certsData = [NSData dataWithContentsOfFile:path];
+  NSCAssert(certsData.length, @"No data read from %@", path);
+  NSString *certsString = [[NSString alloc] initWithData:certsData encoding:NSUTF8StringEncoding];
+  return grpc_ssl_credentials_create(certsString.UTF8String, NULL);
+}
 
 @implementation GRPCSecureChannel
 
 - (instancetype)initWithHost:(NSString *)host {
-  static grpc_credentials *kCredentials;
+  return [self initWithHost:host pathToCertificates:nil hostNameOverride:nil];
+}
+
+- (instancetype)initWithHost:(NSString *)host
+          pathToCertificates:(NSString *)path
+            hostNameOverride:(NSString *)hostNameOverride {
+  // Load default SSL certificates once.
+  static grpc_credentials *kDefaultCertificates;
   static dispatch_once_t loading;
   dispatch_once(&loading, ^{
     // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
@@ -47,15 +59,34 @@
     NSAssert(certsPath.length,
              @"gRPCCertificates.bundle/roots.pem not found under %@. This file, with the root "
              "certificates, is needed to establish TLS (HTTPS) connections.", bundle.bundlePath);
-    NSData *certsData = [NSData dataWithContentsOfFile:certsPath];
-    NSAssert(certsData.length, @"No data read from %@", certsPath);
-    NSString *certsString = [[NSString alloc] initWithData:certsData encoding:NSUTF8StringEncoding];
-    kCredentials = grpc_ssl_credentials_create(certsString.UTF8String, NULL);
+    kDefaultCertificates = CertificatesAtPath(certsPath);
   });
-  return (self = [super initWithChannel:grpc_secure_channel_create(kCredentials,
-                                                                   host.UTF8String,
-                                                                   NULL)
-                               hostName:host]);
+  grpc_credentials *certificates = path ? CertificatesAtPath(path) : kDefaultCertificates;
+
+  // Ritual to pass the SSL host name override to the C library.
+  grpc_channel_args channelArgs;
+  grpc_arg nameOverrideArg;
+  channelArgs.num_args = 1;
+  channelArgs.args = &nameOverrideArg;
+  nameOverrideArg.type = GRPC_ARG_STRING;
+  nameOverrideArg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
+  // Cast const away. Hope C gRPC doesn't modify it!
+  nameOverrideArg.value.string = (char *) hostNameOverride.UTF8String;
+  grpc_channel_args *args = hostNameOverride ? &channelArgs : NULL;
+
+  return [self initWithHost:host credentials:certificates args:args];
+}
+
+- (instancetype)initWithHost:(NSString *)host
+                 credentials:(grpc_credentials *)credentials
+                        args:(grpc_channel_args *)args {
+  return (self =
+          [super initWithChannel:grpc_secure_channel_create(credentials, host.UTF8String, args)]);
+}
+
+- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
+  [NSException raise:NSInternalInconsistencyException format:@"use another initializer"];
+  return [self initWithHost:nil]; // silence warnings
 }
 
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
index 4941cbc3dd1dc1e328e5796e4c764da2aaa7b997..5decfba7e36cdc68ad81f8e4a1f42f9c75da88c5 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
@@ -38,8 +38,11 @@
 @implementation GRPCUnsecuredChannel
 
 - (instancetype)initWithHost:(NSString *)host {
-  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)
-                               hostName:host]);
+  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]);
 }
 
+- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
+  [NSException raise:NSInternalInconsistencyException format:@"use the other initializer"];
+  return [self initWithHost:nil]; // silence warnings
+}
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index db062336aaf4f9a327a956149fc885e1866c72c9..951c0510369fda65442fa12b39fabb783178eb52 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -38,7 +38,8 @@
 #include <grpc/byte_buffer.h>
 #include <grpc/support/alloc.h>
 
-#import "GRPCChannel.h"
+#import "GRPCCompletionQueue.h"
+#import "GRPCHost.h"
 #import "NSDictionary+GRPC.h"
 #import "NSData+GRPC.h"
 #import "NSError+GRPC.h"
@@ -223,8 +224,8 @@
 
 #pragma mark GRPCWrappedCall
 
-@implementation GRPCWrappedCall{
-  GRPCChannel *_channel;
+@implementation GRPCWrappedCall {
+  GRPCCompletionQueue *_queue;
   grpc_call *_call;
 }
 
@@ -245,8 +246,12 @@
       grpc_init();
     });
 
-    _channel = [GRPCChannel channelToHost:host];
-    _call = [_channel unmanagedCallWithPath:path];
+    // Each completion queue consumes one thread. There's a trade to be made between creating and
+    // consuming too many threads and having contention of multiple calls in a single completion
+    // queue. Currently we favor latency and use one per call.
+    _queue = [GRPCCompletionQueue completionQueue];
+
+    _call = [[GRPCHost hostWithAddress:host] unmanagedCallWithPath:path completionQueue:_queue];
     if (_call == NULL) {
       return nil;
     }