diff --git a/ProtoRPC.podspec b/ProtoRPC.podspec
new file mode 100644
index 0000000000000000000000000000000000000000..a7b72f0e460567f39eaf147c37ccdb28a67f9dcb
--- /dev/null
+++ b/ProtoRPC.podspec
@@ -0,0 +1,18 @@
+Pod::Spec.new do |s|
+  s.name     = 'ProtoRPC'
+  s.version  = '0.0.1'
+  s.summary  = 'RPC library for ProtocolBuffers, based on gRPC'
+  s.homepage = 'https://github.com/grpc/grpc/tree/master/src/objective-c/ProtoRPC'
+  s.license  = 'New BSD'
+  s.authors  = { 'Jorge Canizales' => 'jcanizales@google.com' }
+
+  # s.source = { :git => 'https://github.com/grpc/grpc.git', :tag => 'release-0_5_0' }
+  s.source_files = 'src/objective-c/ProtoRPC/*.{h,m}'
+
+  s.platform = :ios
+  s.ios.deployment_target = '6.0'
+  s.requires_arc = true
+
+  s.dependency 'gRPC', '~> 0.0'
+  s.dependency 'RxLibrary', '~> 0.0'
+end
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.h b/src/objective-c/GRPCClient/GRPCMethodName.h
index dcad8a3347989bde4c4040591f7b1f18cc2f0c0c..fe153dd478b2cacd48d6f0079a24191652dd7718 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.h
+++ b/src/objective-c/GRPCClient/GRPCMethodName.h
@@ -37,7 +37,8 @@
 
 // A fully-qualified gRPC method name. Full qualification is needed because a gRPC endpoint can
 // implement multiple interfaces.
-// TODO(jcanizales): Is this proto-specific, or actual part of gRPC? If the former, move one layer up.
+// TODO(jcanizales): Move to ProtoRPC package.
+// TODO(jcanizales): Rename interface -> service.
 @interface GRPCMethodName : NSObject
 @property(nonatomic, readonly) NSString *package;
 @property(nonatomic, readonly) NSString *interface;
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6375f52d6fc648e92ffb811729a95c2ca46ac8e
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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 <gRPC/GRPCCall.h>
+
+@interface ProtoRPC : GRPCCall
+
+- (instancetype)initWithHost:(NSString *)host
+                      method:(GRPCMethodName *)method
+              requestsWriter:(id<GRXWriter>)requestsWriter
+               responseClass:(Class)responseClass
+          responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
+
+- (void)start;
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
new file mode 100644
index 0000000000000000000000000000000000000000..1b046845cef3690f6d0eef42644b5149048e8a7c
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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 "ProtoRPC.h"
+
+#import <RxLibrary/GRXWriteable.h>
+
+@implementation ProtoRPC {
+  id<GRXWriteable> _responseWriteable;
+}
+
+- (instancetype)initWithHost:(NSString *)host
+                      method:(GRPCMethodName *)method
+              requestsWriter:(id<GRXWriter>)requestWriter {
+  return [self initWithHost:host
+                     method:method
+             requestsWriter:requestsWriter
+              responseClass:nil
+        responsesWriteable:nil];
+}
+
+// Designated initializer
+- (instancetype)initWithHost:(NSString *)host
+                      method:(GRPCMethodName *)method
+              requestsWriter:(id<GRXWriter>)requestsWriter
+               responseClass:(Class)responseClass
+          responsesWriteable:(id<GRXWriteable>)responsesWriteable {
+  // Because we can't tell the type system to constrain the class, we need to check at runtime:
+  if (![class respondsToSelector:@selector(parseFromData:)]) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"A protobuf class to parse the responses must be provided."];
+  }
+  if ((self = [super initWithHost:host method:method requestsWriter:requestsWriter])) {
+    _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+      [responsesWriteable didReceiveValue:[responseClass parseFromData:value]];
+    } completionHandler:^(NSError *errorOrNil) {
+      [responsesWriteable didFinishWithError:errorOrNil];
+    }];
+  }
+  return self;
+}
+
+- (void)start {
+  [self startWithWriteable:_responseWriteable];
+}
+
+- (void)startWithWriteable:(id<GRXWriteable>)writeable {
+  [super startWithWriteable:writeable];
+  _responseWriteable = nil;
+}
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h
new file mode 100644
index 0000000000000000000000000000000000000000..c5ef820f48a765692082b1908c1c3f2405797278
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoService.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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>
+
+@class ProtoRPC;
+@protocol GRXWriteable;
+@protocol GRXWriter;
+
+@interface ProtoService : NSObject
+- (instancetype)initWithHost:(NSString *)host
+                 packageName:(NSString *)packageName
+                 serviceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER;
+
+- (ProtoRPC *)RPCToMethod:(NSString *)method
+           requestsWriter:(id<GRXWriter>)requestsWriter
+  	        responseClass:(Class)responseClass
+  	   responsesWriteable:(id<GRXWriteable>)responsesWriteable;
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
new file mode 100644
index 0000000000000000000000000000000000000000..45d015e1316efcfadb52240825c19883cdee914d
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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 "ProtoService.h"
+
+#import <gRPC/GRPCMethodName.h>
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter.h>
+
+#import "ProtoRPC.h"
+
+@implementation ProtoService {
+  NSString *_host;
+  NSString *_packageName;
+  NSString *_serviceName;
+}
+
+- (instancetype)init {
+  return [self initWithHost:nil];
+}
+
+// Designated initializer
+- (instancetype)initWithHost:(NSString *)host
+                 packageName:(NSString *)packageName
+                 serviceName:(NSString *)serviceName {
+  if (!host || !serviceName) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"Neither host nor serviceName can be nil."];
+  }
+  if ((self = [super init])) {
+    _host = [host copy];
+    _packageName = [packageName copy];
+    _serviceName = [serviceName copy];
+  }
+  return self;
+}
+
+- (ProtoRPC *)RPCToMethod:(NSString *)method
+           requestsWriter:(id<GRXWriter>)requestsWriter
+            responseClass:(Class)responseClass
+       responsesWriteable:(id<GRXWriteable>)responsesWriteable {
+  GRPCMethodName *methodName = [[GRPCMethodName alloc] initWithPackage:_packageName
+                                                             interface:_serviceName
+                                                                method:_method];
+  return [[ProtoRPC alloc] initWithHost:_host
+                                 method:methodName
+                         requestsWriter:requestsWriter
+                          responseClass:responseClass
+                     responsesWriteable:responsesWriteable];
+}
+@end
diff --git a/src/objective-c/RxLibrary/GRXWriteable.h b/src/objective-c/RxLibrary/GRXWriteable.h
index cdcb99f4590a2b130744ebfdd8848a0b383b9680..6f6ea142e01d90fe604ad55d90c3204178554093 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.h
+++ b/src/objective-c/RxLibrary/GRXWriteable.h
@@ -50,10 +50,16 @@
 
 typedef void (^GRXValueHandler)(id value);
 typedef void (^GRXCompletionHandler)(NSError *errorOrNil);
+typedef void (^GRXSingleValueHandler)(id value, NSError *errorOrNil);
+typedef void (^GRXStreamHandler)(BOOL done, id value, NSError *error);
 
 // Utility to create objects that conform to the GRXWriteable protocol, from
 // blocks that handle each of the two methods of the protocol.
 @interface GRXWriteable : NSObject<GRXWriteable>
+
++ (instancetype)writeableWithSingleValueHandler:(GRXSingleValueHandler)handler;
++ (instancetype)writeableWithStreamHandler:(GRXStreamHandler)handler;
+
 - (instancetype)initWithValueHandler:(GRXValueHandler)valueHandler
                    completionHandler:(GRXCompletionHandler)completionHandler
     NS_DESIGNATED_INITIALIZER;
diff --git a/src/objective-c/RxLibrary/GRXWriteable.m b/src/objective-c/RxLibrary/GRXWriteable.m
index 7231f06462a823bbab952ce4c623d5e17f85d084..7000a078d1e014e825d8a973a2d2f8bd5302f351 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.m
+++ b/src/objective-c/RxLibrary/GRXWriteable.m
@@ -38,6 +38,30 @@
   GRXCompletionHandler _completionHandler;
 }
 
++ (instancetype)writeableWithSingleValueHandler:(GRXSingleValueHandler)handler {
+  if (!handler) {
+    return [[self alloc] init];
+  }
+  return [[self alloc] initWithValueHandler:^(id value) {
+    handler(value, nil);
+  } completionHandler:^(NSError *errorOrNil) {
+    if (errorOrNil) {
+      handler(nil, errorOrNil);
+    }
+  }];
+}
+
++ (instancetype)writeableWithStreamHandler:(GRXStreamHandler)handler {
+  if (!handler) {
+    return [[self alloc] init];
+  }
+  return [[self alloc] initWithValueHandler:^(id value) {
+    handler(NO, value, nil);
+  } completionHandler:^(NSError *errorOrNil) {
+    handler(YES, nil, errorOrNil);
+  }];
+}
+
 - (instancetype)init {
   return [self initWithValueHandler:nil completionHandler:nil];
 }
diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile
index 8b1a90e39bd0372849557d7d2ccac9797da6e4d9..7752d240d095bc2961c0c5435bbf2e6d3094e4a0 100644
--- a/src/objective-c/examples/Sample/Podfile
+++ b/src/objective-c/examples/Sample/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
 pod 'gRPC', :path => "../../../.."
+pod 'ProtoRPC', :path => "../../../.."
 pod 'Route_guide', :path => "RouteGuideClient"
 pod 'RemoteTest', :path => "RemoteTestClient"
 
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
index 4790594bc5ba45fc1979c455b32b6c14e4cbe3aa..8770804617a7a18ef940c4963e97a7e0bc50e42c 100644
--- a/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
@@ -14,4 +14,5 @@ Pod::Spec.new do |s|
   s.requires_arc = true
 
   s.dependency 'ProtocolBuffers', '~> 1.9'
+  s.dependency 'ProtoRPC', '~> 0.0'
 end
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h
index 6db981dc5bb9d8c6772df4f3b32eb47e0a15d308..92c58a1652d6e90b68cc16f49c1ee012dfe6c6a4 100644
--- a/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h
@@ -4,6 +4,7 @@
 
 #import "Empty.pb.h"
 #import "Messages.pb.h"
+#import <ProtoRPC/ProtoService.h>
 // @@protoc_insertion_point(imports)
 
 @class ObjectiveCFileOptions;
@@ -78,4 +79,88 @@
 @end
 
 
+
+@protocol GRXWriteable;
+@protocol GRXWriter;
+
+@protocol RMTTestService <NSObject>
+
+#pragma mark EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty)
+
+// One empty request followed by one empty response.
+- (void)emptyCallWithRequest:(RMTEmpty *)request
+                     handler:(void(^)(RMTEmpty *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToEmptyCallWithRequest:(RMTEmpty *)request
+                                handler:(void(^)(RMTEmpty *response, NSError *error))handler;
+
+
+#pragma mark UnaryCall(SimpleRequest) returns (SimpleResponse)
+
+// One request followed by one response.
+- (void)unaryCallWithRequest:(RMTSimpleRequest *)request
+                     handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToUnaryCallWithRequest:(RMTSimpleRequest *)request
+                                handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler;
+
+
+#pragma mark StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// One request followed by a sequence of responses (streamed download).
+// The server returns the payload with client desired type and sizes.
+- (void)streamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+                               handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+                                          handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+
+#pragma mark StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse)
+
+// A sequence of requests followed by one response (streamed upload).
+// The server returns the aggregated size of client payload as the result.
+- (void)streamingInputCallWithRequestsWriter:(id<GRXWriter>)request
+                                     handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingInputCallWithRequestsWriter:(id<GRXWriter>)request
+                                                handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler;
+
+
+#pragma mark FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// A sequence of requests with each request served by the server immediately.
+// As one request could lead to multiple responses, this interface
+// demonstrates the idea of full duplexing.
+- (void)fullDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+                                 handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToFullDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+                                            handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+
+#pragma mark HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// A sequence of requests followed by a sequence of responses.
+// The server buffers all the client requests and then serves them in order. A
+// stream of responses are returned to the client when the server starts with
+// first request.
+- (void)halfDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+                                 handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToHalfDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+                                            handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+@end
+
+// Basic service implementation, over gRPC, that only does marshalling and parsing.
+@interface RMTTestService : ProtoService<RMTTestService>
+@end
+
 // @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m
index bd6a29df413ea3968858912e9256e966884b1978..b05bcc7218f768282a705ae01911ff721f3dde99 100644
--- a/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m
@@ -1,6 +1,9 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
 
 #import "Test.pb.h"
+
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
 // @@protoc_insertion_point(imports)
 
 @implementation RMTTestRoot
@@ -24,4 +27,129 @@ static PBExtensionRegistry* extensionRegistry = nil;
 @end
 
 
+static NSString *const kServiceName = @"grpc.testing.TestService";
+
+@implementation RMTTestService
+
+- (instancetype)initWithHost:(NSString *)host {
+  return (self = [super initWithHost:host serviceName:kServiceName]);
+}
+
+
+#pragma mark EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty)
+
+// One empty request followed by one empty response.
+- (void)emptyCallWithRequest:(RMTEmpty *)request
+                     handler:(void(^)(RMTEmpty *response, NSError *error))handler {
+  [[self RPCToEmptyCallWithRequest:request handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToEmptyCallWithRequest:(RMTEmpty *)request
+                                handler:(void(^)(RMTEmpty *response, NSError *error))handler {
+  return [self RPCToMethod:@"EmptyCall"
+            requestsWriter:[GRXWriter writerWithValue:request];
+             responseClass:[RMTEmpty class]
+        responsesWriteable:[GRXWriteable writeableWithSingleValueHandler:handler]];
+}
+
+
+#pragma mark UnaryCall(SimpleRequest) returns (SimpleResponse)
+
+// One request followed by one response.
+- (void)unaryCallWithRequest:(RMTSimpleRequest *)request
+                     handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler {
+  [[self RPCToUnaryCallWithRequest:request handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToUnaryCallWithRequest:(RMTSimpleRequest *)request
+                                handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler {
+  return [self RPCToMethod:@"UnaryCall"
+            requestsWriter:[GRXWriter writerWithValue:request];
+             responseClass:[RMTSimpleResponse class]
+        responsesWriteable:[GRXWriteable writeableWithSingleValueHandler:handler]];
+}
+
+
+#pragma mark StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// One request followed by a sequence of responses (streamed download).
+// The server returns the payload with client desired type and sizes.
+- (void)streamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+                               handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+  [[self RPCToStreamingOutputCallWithRequest:request handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+                                          handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+  return [self RPCToMethod:@"StreamingOutputCall"
+            requestsWriter:[GRXWriter writerWithValue:request];
+             responseClass:[RMTStreamingOutputCallResponse class]
+        responsesWriteable:[GRXWriteable writeableWithStreamHandler:handler]];
+}
+
+
+#pragma mark StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse)
+
+// A sequence of requests followed by one response (streamed upload).
+// The server returns the aggregated size of client payload as the result.
+- (void)streamingInputCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+                                     handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler {
+  [[self RPCToStreamingInputCallWithRequestsWriter:requestsWriter handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingInputCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+                                                handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler {
+  return [self RPCToMethod:@"StreamingInputCall"
+            requestsWriter:requestsWriter;
+             responseClass:[RMTStreamingInputCallResponse class]
+        responsesWriteable:[GRXWriteable writeableWithSingleValueHandler:handler]];
+}
+
+
+#pragma mark FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// A sequence of requests with each request served by the server immediately.
+// As one request could lead to multiple responses, this interface
+// demonstrates the idea of full duplexing.
+- (void)fullDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+                                 handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+  [[self RPCToFullDuplexCallWithRequestsWriter:requestsWriter handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToFullDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+                                            handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+  return [self RPCToMethod:@"FullDuplexCall"
+            requestsWriter:requestsWriter;
+             responseClass:[RMTStreamingOutputCallResponse class]
+        responsesWriteable:[GRXWriteable writeableWithStreamHandler:handler]];
+}
+
+
+#pragma mark HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// A sequence of requests followed by a sequence of responses.
+// The server buffers all the client requests and then serves them in order. A
+// stream of responses are returned to the client when the server starts with
+// first request.
+- (void)halfDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+                                 handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+  [[self RPCToHalfDuplexCallWithRequestsWriter:requestsWriter handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToHalfDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+                                            handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+  return [self RPCToMethod:@"HalfDuplexCall"
+            requestsWriter:requestsWriter;
+             responseClass:[RMTStreamingOutputCallResponse class]
+        responsesWriteable:[GRXWriteable writeableWithStreamHandler:handler]];
+}
+
+@end
+
 // @@protoc_insertion_point(global_scope)