diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 587d86c98fd79eb81cf8a77385dc82590fe05c9d..dbd125e57ad03b014c18f3321a302cd9c969f9b1 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -237,6 +237,10 @@ GRPCAPI struct census_context *grpc_census_call_get_context(grpc_call *call);
     created for. */
 GRPCAPI char *grpc_channel_get_target(grpc_channel *channel);
 
+/** Request info about the channel. */
+GRPCAPI void grpc_channel_get_info(grpc_channel *channel,
+                                   grpc_channel_info *channel_info);
+
 /** Create a client channel to 'target'. Additional channel level configuration
     MAY be provided by grpc_channel_args, though the expectation is that most
     clients will want to simply pass NULL. See grpc_channel_args definition for
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 0be7ab2ad2353a2c239e0a263ab6ef5b12081910..0fc86b57cc15f41b5a5254ab01ad72441feec89a 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -467,6 +467,13 @@ typedef struct grpc_op {
   } data;
 } grpc_op;
 
+/** Information requested from the channel. */
+typedef struct {
+  /* If non-NULL, will be set to point to a string indicating the LB
+   * policy name.  Caller takes ownership. */
+  char **lb_policy_name;
+} grpc_channel_info;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index a4cf6f37bd7a005c6b18957290ce98a3f1cf132a..7ace2f671e1d6e1e99d5fb73c7ef494afdec024c 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -191,6 +191,7 @@ const grpc_channel_filter grpc_client_census_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "census-client"};
 
 const grpc_channel_filter grpc_server_census_filter = {
@@ -204,4 +205,5 @@ const grpc_channel_filter grpc_server_census_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "census-server"};
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 80b4f048c2facbca8d6f8a76936a3536a6c835f0..d15af0b438c3f55a05f521e26e0157c0c65fb2e8 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -39,6 +39,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
@@ -123,6 +124,7 @@ typedef struct client_channel_channel_data {
   /** mutex protecting all variables below in this data structure */
   gpr_mu mu;
   /** currently active load balancer */
+  char* lb_policy_name;
   grpc_lb_policy *lb_policy;
   /** maps method names to method_parameters structs */
   grpc_mdstr_hash_table *method_params_table;
@@ -223,6 +225,7 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
 static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
                                        grpc_error *error) {
   channel_data *chand = arg;
+  char *lb_policy_name = NULL;
   grpc_lb_policy *lb_policy = NULL;
   grpc_lb_policy *old_lb_policy;
   grpc_mdstr_hash_table *method_params_table = NULL;
@@ -236,12 +239,11 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
     lb_policy_args.client_channel_factory = chand->client_channel_factory;
 
     // Find LB policy name.
-    const char *lb_policy_name = NULL;
     const grpc_arg *channel_arg =
         grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME);
     if (channel_arg != NULL) {
       GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-      lb_policy_name = channel_arg->value.string;
+      lb_policy_name = gpr_strdup(channel_arg->value.string);
     }
     // Special case: If all of the addresses are balancer addresses,
     // assume that we should use the grpclb policy, regardless of what the
@@ -265,13 +267,14 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
                   "addresses, no backend addresses -- forcing use of grpclb LB "
                   "policy",
                   lb_policy_name);
+          gpr_free(lb_policy_name);
         }
-        lb_policy_name = "grpclb";
+        lb_policy_name = gpr_strdup("grpclb");
       }
     }
     // Use pick_first if nothing was specified and we didn't select grpclb
     // above.
-    if (lb_policy_name == NULL) lb_policy_name = "pick_first";
+    if (lb_policy_name == NULL) lb_policy_name = gpr_strdup("pick_first");
 
     lb_policy =
         grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
@@ -299,6 +302,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
   }
 
   gpr_mu_lock(&chand->mu);
+  if (lb_policy_name != NULL) {
+    gpr_free(chand->lb_policy_name);
+    chand->lb_policy_name = lb_policy_name;
+  }
   old_lb_policy = chand->lb_policy;
   chand->lb_policy = lb_policy;
   if (chand->method_params_table != NULL) {
@@ -426,6 +433,18 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
   gpr_mu_unlock(&chand->mu);
 }
 
+static void cc_get_channel_info(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem,
+                                grpc_channel_info *info) {
+  channel_data *chand = elem->channel_data;
+  gpr_mu_lock(&chand->mu);
+  if (info->lb_policy_name != NULL) {
+    *info->lb_policy_name = chand->lb_policy_name == NULL
+                                ? NULL : gpr_strdup(chand->lb_policy_name);
+  }
+  gpr_mu_unlock(&chand->mu);
+}
+
 /* Constructor for channel_data */
 static void cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem,
@@ -465,6 +484,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                      chand->interested_parties);
     GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
   }
+  gpr_free(chand->lb_policy_name);
   if (chand->method_params_table != NULL) {
     grpc_mdstr_hash_table_unref(chand->method_params_table);
   }
@@ -1048,6 +1068,7 @@ const grpc_channel_filter grpc_client_channel_filter = {
     cc_init_channel_elem,
     cc_destroy_channel_elem,
     cc_get_peer,
+    cc_get_channel_info,
     "client-channel",
 };
 
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index eeae2400fbc80c8dd1cd37a35bbd7b73ff333b05..b810e20bb98d56e6e70034a95f99b6a4731346a3 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -232,4 +232,5 @@ const grpc_channel_filter grpc_load_reporting_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "load_reporting"};
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 2c5367901dfdc7bf8da013985384414f32edce9e..3370f0ef459790b7c52d11515afc77f46d725400 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -255,6 +255,13 @@ char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx,
   return next_elem->filter->get_peer(exec_ctx, next_elem);
 }
 
+void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem,
+                                grpc_channel_info *channel_info) {
+  grpc_channel_element *next_elem = elem + 1;
+  return next_elem->filter->get_channel_info(exec_ctx, next_elem, channel_info);
+}
+
 void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
                           grpc_transport_op *op) {
   grpc_channel_element *next_elem = elem + 1;
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 27f3be7b29116ae98b8ce3d3ac727b104d47b4f3..6fbcd870641588c6a80292f992ab95d922e7f426 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -156,6 +156,10 @@ typedef struct {
   /* Implement grpc_call_get_peer() */
   char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
 
+  /* Implement grpc_channel_get_info() */
+  void (*get_channel_info)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+                           grpc_channel_info *channel_info);
+
   /* The name of this filter */
   const char *name;
 } grpc_channel_filter;
@@ -273,6 +277,10 @@ void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
                           grpc_transport_op *op);
 /* Pass through a request to get_peer to the next child element */
 char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+/* Pass through a request to get_channel_info() to the next child element */
+void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem,
+                                grpc_channel_info *channel_info);
 
 /* Given the top element of a channel stack, get the channel stack itself */
 grpc_channel_stack *grpc_channel_stack_from_top_element(
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 0981d59f637c7de9f0bfa7365576a90a286d0eb0..7968cf7e2655f6ff3bc0e8147893547d56e19e67 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -328,4 +328,5 @@ const grpc_channel_filter grpc_compress_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "compress"};
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 918379c8457f4ee8ed0b6c2f0fb091b4fea31a92..6ae2b3b6b7bd4be4ea85585051a005fd9a417832 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -134,6 +134,11 @@ static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
   return grpc_transport_get_peer(exec_ctx, chand->transport);
 }
 
+/* No-op. */
+static void con_get_channel_info(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem,
+                                 grpc_channel_info *channel_info) {}
+
 static const grpc_channel_filter connected_channel_filter = {
     con_start_transport_stream_op,
     con_start_transport_op,
@@ -145,6 +150,7 @@ static const grpc_channel_filter connected_channel_filter = {
     init_channel_elem,
     destroy_channel_elem,
     con_get_peer,
+    con_get_channel_info,
     "connected",
 };
 
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index d2ea5250f6c96ff2fd0cf212880299406435f994..224c823a4f4ff0ba603a28f38c2033f6e58de940 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -316,6 +316,7 @@ const grpc_channel_filter grpc_client_deadline_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "deadline",
 };
 
@@ -330,5 +331,6 @@ const grpc_channel_filter grpc_server_deadline_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "deadline",
 };
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 1dc05fb20d1a03b4f144b3f69db5c05136142fab..b5ab4dd5cac8f5f51029e5a60a146b2dce877a57 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -448,4 +448,5 @@ const grpc_channel_filter grpc_http_client_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "http-client"};
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index f2221fb0fbe3e939279e105acf7acbbd53826bc6..d02a765d0d8384b1eaa3378652c95b67d2463772 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -344,4 +344,5 @@ const grpc_channel_filter grpc_http_server_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "http-server"};
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 7dc5ae0df150632aeee44d42f254c2dfbeb8f4b5..bbcd2a21453095d61e83f373eb0cb5e897cdafd6 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -248,4 +248,5 @@ const grpc_channel_filter grpc_message_size_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "message_size"};
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index b366d1410f9ad16b8b73995d7414201ce5df17a3..3a96af2c6985d1b439476da6a1b6f742aec622a7 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -351,4 +351,5 @@ const grpc_channel_filter grpc_client_auth_filter = {auth_start_transport_op,
                                                      init_channel_elem,
                                                      destroy_channel_elem,
                                                      grpc_call_next_get_peer,
+                                                     grpc_channel_next_get_info,
                                                      "client-auth"};
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index b2c6815af81dd2914f83068a73de8b7712f474f7..8ecc5fd088393ddabe50bf2d6520b00404a4cfa0 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -278,4 +278,5 @@ const grpc_channel_filter grpc_server_auth_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "server-auth"};
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index 92d783b78da4ea4510467d9b94461b958723f304..22bf85b126126b1afb02acd44d8d4c7189940868 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -175,6 +175,15 @@ char *grpc_channel_get_target(grpc_channel *channel) {
   return gpr_strdup(channel->target);
 }
 
+void grpc_channel_get_info(grpc_channel *channel,
+                           grpc_channel_info *channel_info) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_channel_element *elem =
+      grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
+  elem->filter->get_channel_info(&exec_ctx, elem, channel_info);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
 static grpc_call *grpc_channel_create_call_internal(
     grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
     grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index d32c884e8ea32496b9d8e67917306a4cb6e0ffd1..6fd1dd921c8dbc841c550ddd484b9c6f6196c6b7 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -88,6 +88,10 @@ static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
   return NULL;
 }
 
+static void lame_get_channel_info(grpc_exec_ctx *exec_ctx,
+                                  grpc_channel_element *elem,
+                                  grpc_channel_info *channel_info) {}
+
 static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
                                     grpc_channel_element *elem,
                                     grpc_transport_op *op) {
@@ -140,6 +144,7 @@ const grpc_channel_filter grpc_lame_filter = {
     init_channel_elem,
     destroy_channel_elem,
     lame_get_peer,
+    lame_get_channel_info,
     "lame-client",
 };
 
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 3a90308058c7f03c510c85f6553995c17178f8fb..914b62e176033dc8274cef2381d6a04ae0bec496 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -965,6 +965,7 @@ const grpc_channel_filter grpc_server_top_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "server",
 };
 
diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c
index 844db5e6cb5b370056c32c9c53689ed700bc6891..857ba6bd52095afe7f8c06603144f393b94427f6 100644
--- a/test/core/client_channel/lb_policies_test.c
+++ b/test/core/client_channel/lb_policies_test.c
@@ -638,6 +638,21 @@ static void test_pending_calls(size_t concurrent_calls) {
   test_spec_destroy(spec);
 }
 
+static void test_get_channel_info() {
+  grpc_channel *channel = grpc_insecure_channel_create(
+      "test:127.0.0.1:1234?lb_policy=round_robin", NULL, NULL);
+  // Ensures that resolver returns.
+  grpc_channel_check_connectivity_state(channel, true /* try_to_connect */);
+  char *lb_policy_name = NULL;
+  grpc_channel_info channel_info;
+  channel_info.lb_policy_name = &lb_policy_name;
+  grpc_channel_get_info(channel, &channel_info);
+  GPR_ASSERT(lb_policy_name != NULL);
+  GPR_ASSERT(strcmp(lb_policy_name, "round_robin") == 0);
+  gpr_free(lb_policy_name);
+  grpc_channel_destroy(channel);
+}
+
 static void print_failed_expectations(const int *expected_connection_sequence,
                                       const int *actual_connection_sequence,
                                       const size_t expected_seq_length,
@@ -933,6 +948,7 @@ int main(int argc, char **argv) {
 
   test_pending_calls(4);
   test_ping();
+  test_get_channel_info();
 
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index 0e5692f4c9f616a195f0fbe10cdbdf0c0bf11841..2f8a2a4d0460377bca753d81001a1bdc0a100cdb 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -231,6 +231,7 @@ static const grpc_channel_filter test_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "filter_call_init_fails"};
 
 /*******************************************************************************
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index d5eddc7330b1ce74a7cc8bea0bd140c074669fdd..da554142e8b4e3202089118fd05a756124a53dbd 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -258,6 +258,7 @@ static const grpc_channel_filter test_filter = {
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "filter_causes_close"};
 
 /*******************************************************************************