diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index a3fc683e579b4eb8095f2288233ff6cb083dee00..0be7ab2ad2353a2c239e0a263ab6ef5b12081910 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -204,6 +204,13 @@ typedef struct {
 /** Service config data, to be passed to subchannels.
     Not intended for external use. */
 #define GRPC_ARG_SERVICE_CONFIG "grpc.service_config"
+/** LB policy name. */
+#define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name"
+/** Server name. Not intended for external use. */
+#define GRPC_ARG_SERVER_NAME "grpc.server_name"
+/** Resolved addresses in a form used by the LB policy.
+    Not intended for external use. */
+#define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses"
 /** \} */
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a
diff --git a/src/core/ext/client_config/lb_policy_factory.c b/src/core/ext/client_config/lb_policy_factory.c
index 55e346180de13741ae043500b8c9c5535c7a958f..676fdaf555fe7c08b0dc141e86d5d8b5c92e8731 100644
--- a/src/core/ext/client_config/lb_policy_factory.c
+++ b/src/core/ext/client_config/lb_policy_factory.c
@@ -124,6 +124,28 @@ void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) {
   gpr_free(addresses);
 }
 
+static void* lb_addresses_copy(void* addresses) {
+  return grpc_lb_addresses_copy(addresses);
+}
+static void lb_addresses_destroy(void* addresses) {
+  grpc_lb_addresses_destroy(addresses);
+}
+static int lb_addresses_cmp(void* addresses1, void* addresses2) {
+  return grpc_lb_addresses_cmp(addresses1, addresses2);
+}
+static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = {
+    lb_addresses_copy, lb_addresses_destroy, lb_addresses_cmp};
+
+grpc_arg grpc_lb_addresses_create_channel_arg(
+    const grpc_lb_addresses *addresses) {
+  grpc_arg arg;
+  arg.type = GRPC_ARG_POINTER;
+  arg.key = GRPC_ARG_LB_ADDRESSES;
+  arg.value.pointer.p = (void*)addresses;
+  arg.value.pointer.vtable = &lb_addresses_arg_vtable;
+  return arg;
+}
+
 void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) {
   factory->vtable->ref(factory);
 }
diff --git a/src/core/ext/client_config/lb_policy_factory.h b/src/core/ext/client_config/lb_policy_factory.h
index 61c3f419d138a6c14dec59138892293b80206f33..f0798a316740ae422fd0131bd4aea22908614c3a 100644
--- a/src/core/ext/client_config/lb_policy_factory.h
+++ b/src/core/ext/client_config/lb_policy_factory.h
@@ -97,6 +97,10 @@ int grpc_lb_addresses_cmp(const grpc_lb_addresses *addresses1,
  * be invoked to destroy the \a user_data field of each address. */
 void grpc_lb_addresses_destroy(grpc_lb_addresses *addresses);
 
+/** Returns a channel arg containing \a addresses. */
+grpc_arg grpc_lb_addresses_create_channel_arg(
+    const grpc_lb_addresses *addresses);
+
 /** Arguments passed to LB policies. */
 /* TODO(roth, ctiller): Consider replacing this struct with
    grpc_channel_args.  See comment in resolver_result.h for details. */
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 0694d8b6b77d9b6a3d1ef0fa9da56fb377aa2911..039fb2225d50bfa4cb90f3a5c56429a177d80af7 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -55,6 +55,7 @@ typedef struct {
   /** base class: must be first */
   grpc_resolver base;
   /** target name */
+// FIXME: remove target_name when resolver_result goes away
   char *target_name;
   /** name to resolve (usually the same as target_name) */
   char *name_to_resolve;
@@ -178,10 +179,12 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
           r->addresses->addrs[i].len, false /* is_balancer */,
           NULL /* balancer_name */, NULL /* user_data */);
     }
+    grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses);
+    grpc_channel_args* args =
+        grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
     grpc_resolved_addresses_destroy(r->addresses);
     result = grpc_resolver_result_create(
-        r->target_name, addresses, NULL /* lb_policy_name */,
-        grpc_channel_args_copy(r->channel_args));
+        r->target_name, addresses, NULL /* lb_policy_name */, args);
   } else {
     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
     gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
@@ -268,7 +271,12 @@ static grpc_resolver *dns_create(grpc_resolver_args *args,
   r->target_name = gpr_strdup(path);
   r->name_to_resolve = proxy_name == NULL ? gpr_strdup(path) : proxy_name;
   r->default_port = gpr_strdup(default_port);
-  r->channel_args = grpc_channel_args_copy(args->args);
+  grpc_arg server_name_arg;
+  server_name_arg.type = GRPC_ARG_STRING;
+  server_name_arg.key = GRPC_ARG_SERVER_NAME;
+  server_name_arg.value.string = (char*)path;
+  r->channel_args =
+      grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
   gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER,
                    BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000);
   return &r->base;
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index d34094f8e8b313d7bde4c0bf8b0dcd65d6b2c6e9..93a34bf305f455347edd94ce01d2a511255838ee 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -52,6 +52,7 @@ typedef struct {
   /** base class: must be first */
   grpc_resolver base;
   /** the path component of the uri passed in */
+// FIXME: remove target_name when resolver_result goes away
   char *target_name;
   /** the addresses that we've 'resolved' */
   grpc_lb_addresses *addresses;
@@ -120,9 +121,12 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
                                               sockaddr_resolver *r) {
   if (r->next_completion != NULL && !r->published) {
     r->published = true;
+    grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
+    grpc_channel_args* args =
+        grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
     *r->target_result = grpc_resolver_result_create(
         r->target_name, grpc_lb_addresses_copy(r->addresses),
-        NULL /* lb_policy_name */, grpc_channel_args_copy(r->channel_args));
+        NULL /* lb_policy_name */, args);
     grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
     r->next_completion = NULL;
   }
@@ -204,7 +208,12 @@ static grpc_resolver *sockaddr_create(grpc_resolver_args *args,
   memset(r, 0, sizeof(*r));
   r->target_name = gpr_strdup(args->uri->path);
   r->addresses = addresses;
-  r->channel_args = grpc_channel_args_copy(args->args);
+  grpc_arg server_name_arg;
+  server_name_arg.type = GRPC_ARG_STRING;
+  server_name_arg.key = GRPC_ARG_SERVER_NAME;
+  server_name_arg.value.string = args->uri->path;
+  r->channel_args =
+      grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
   gpr_mu_init(&r->mu);
   grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
   return &r->base;
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 67337f4f84118b52b6c90f0c8d6afd173bedc1bf..f77f3eb27d2d91f66f0cd198f84a7d7507a46b4f 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -59,7 +59,9 @@ typedef struct {
   grpc_resolver base;
 
   // passed-in parameters
+// FIXME: remove target_name once resolver_result is removed
   char* target_name;  // the path component of the uri passed in
+  grpc_channel_args* channel_args;
   grpc_lb_addresses* addresses;
   char* lb_policy_name;
   grpc_method_config_table* method_config_table;
@@ -78,6 +80,7 @@ static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) {
   fake_resolver* r = (fake_resolver*)gr;
   gpr_mu_destroy(&r->mu);
   gpr_free(r->target_name);
+  grpc_channel_args_destroy(r->channel_args);
   grpc_lb_addresses_destroy(r->addresses);
   gpr_free(r->lb_policy_name);
   grpc_method_config_table_unref(r->method_config_table);
@@ -100,15 +103,24 @@ static void fake_resolver_maybe_finish_next_locked(grpc_exec_ctx* exec_ctx,
                                                    fake_resolver* r) {
   if (r->next_completion != NULL && !r->published) {
     r->published = true;
-    grpc_channel_args* lb_policy_args = NULL;
+    grpc_arg new_args[3];
+    size_t num_args = 0;
+    new_args[num_args++] = grpc_lb_addresses_create_channel_arg(r->addresses);
     if (r->method_config_table != NULL) {
-      const grpc_arg arg =
+      new_args[num_args++] =
           grpc_method_config_table_create_channel_arg(r->method_config_table);
-      lb_policy_args = grpc_channel_args_copy_and_add(NULL /* src */, &arg, 1);
     }
+    if (r->lb_policy_name != NULL) {
+      new_args[num_args].type = GRPC_ARG_STRING;
+      new_args[num_args].key = GRPC_ARG_LB_POLICY_NAME;
+      new_args[num_args].value.string = r->lb_policy_name;
+      ++num_args;
+    }
+    grpc_channel_args* args =
+        grpc_channel_args_copy_and_add(r->channel_args, new_args, num_args);
     *r->target_result = grpc_resolver_result_create(
         r->target_name, grpc_lb_addresses_copy(r->addresses),
-        r->lb_policy_name, lb_policy_args);
+        r->lb_policy_name, args);
     grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
     r->next_completion = NULL;
   }
@@ -233,6 +245,12 @@ static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
   fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
   memset(r, 0, sizeof(*r));
   r->target_name = gpr_strdup(args->uri->path);
+  grpc_arg server_name_arg;
+  server_name_arg.type = GRPC_ARG_STRING;
+  server_name_arg.key = GRPC_ARG_SERVER_NAME;
+  server_name_arg.value.string = r->target_name;
+  r->channel_args =
+      grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
   r->addresses = addresses;
   r->lb_policy_name =
       gpr_strdup(grpc_uri_get_query_arg(args->uri, "lb_policy"));