diff --git a/BUILD b/BUILD
index 75ac82745edd801133b02f354f929026a37ef01d..b530e9c38b97471026eab97861009e92e21389a0 100644
--- a/BUILD
+++ b/BUILD
@@ -998,6 +998,7 @@ grpc_cc_library(
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c",
+        "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c",
     ],
     hdrs = [
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 719cee6dfa717f205b5a71a9a0565c392302af7c..3b51bcd8ad14cc408670413d2f7e7236dbbb5290 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1133,6 +1133,7 @@ add_library(grpc
   src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c
   src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
   src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
   src/core/ext/filters/load_reporting/load_reporting.c
@@ -2014,6 +2015,7 @@ add_library(grpc_unsecure
   src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+  src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c
   src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c
   src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c
   src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c
diff --git a/Makefile b/Makefile
index cbc96e0add2bd5f06b6067a086fc0b84bc91734c..bc84ccc6ca62bd8bc36bc57fac94f3bf76c188dd 100644
--- a/Makefile
+++ b/Makefile
@@ -3116,6 +3116,7 @@ LIBGRPC_SRC = \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c \
     src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
     src/core/ext/filters/load_reporting/load_reporting.c \
@@ -3966,6 +3967,7 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c \
     src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
     src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c \
diff --git a/binding.gyp b/binding.gyp
index 41400dcad5154971a31bf2f872dc5b1374962aaf..ecc4b04a3a78af8c27887a4edd82aea615c6eae6 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -864,6 +864,7 @@
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
         'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c',
         'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
         'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
         'src/core/ext/filters/load_reporting/load_reporting.c',
diff --git a/build.yaml b/build.yaml
index c3d0d2364df6e81e9d7e60420258741e4640d30a..152183be34821b0a179052d6acd95bcbfdaaf5e0 100644
--- a/build.yaml
+++ b/build.yaml
@@ -594,6 +594,7 @@ filegroups:
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
   - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+  - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c
   plugin: grpc_resolver_dns_ares
   uses:
   - grpc_base
diff --git a/config.m4 b/config.m4
index 6a5cc61a24f03a5b8e4bd177fb73d7708d15b6ce..fc20e8a8d561c5b2cbb44731a43eadddded2a3e5 100644
--- a/config.m4
+++ b/config.m4
@@ -311,6 +311,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
+    src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c \
     src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
     src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c \
     src/core/ext/filters/load_reporting/load_reporting.c \
diff --git a/config.w32 b/config.w32
index 3fa30f1b533a36faef71f3038982cdc5576aa6ac..57831a2ae91fbd851ee70e931e0640e8b9edcb23 100644
--- a/config.w32
+++ b/config.w32
@@ -288,6 +288,7 @@ if (PHP_GRPC != "no") {
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.c " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.c " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.c " +
+    "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_fallback.c " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native\\dns_resolver.c " +
     "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.c " +
     "src\\core\\ext\\filters\\load_reporting\\load_reporting.c " +
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 53403d90a2e37ade194ff4c5c5e1bcaf08abc771..0327c9944b3b60dda85e9afce0c4e2c82f5772eb 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -690,6 +690,7 @@ Pod::Spec.new do |s|
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
                       'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+                      'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c',
                       'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
                       'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
                       'src/core/ext/filters/load_reporting/load_reporting.c',
diff --git a/grpc.gemspec b/grpc.gemspec
index 28e6dafa6c52e21ab248a7e96cf38651a1352c4a..946b1b4bf295327f29adfa6ac591f1468aff6c7e 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -621,6 +621,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c )
+  s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c )
   s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c )
   s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c )
   s.files += %w( src/core/ext/filters/load_reporting/load_reporting.c )
diff --git a/package.xml b/package.xml
index 64a5a6f22a6a794b15b631fc8277f14c3ac1d16b..df0aee4865be93d1ca4dee0b65292c67098357ba 100644
--- a/package.xml
+++ b/package.xml
@@ -635,6 +635,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/load_reporting/load_reporting.c" role="src" />
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
index a0e6604f38f50a6bb1edf1ccdc4ed1bec3f80d34..2bf44a4f1b44db2066f002139e5b79ac3b9851aa 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
@@ -65,6 +65,8 @@ typedef struct {
   grpc_combiner *combiner;
   /** are we currently resolving? */
   bool resolving;
+  /** the pending resolving request */
+  grpc_ares_request *pending_request;
   /** which version of the result have we published? */
   int published_version;
   /** which version of the result is current? */
@@ -82,7 +84,7 @@ typedef struct {
   gpr_backoff backoff_state;
 
   /** currently resolving addresses */
-  grpc_resolved_addresses *addresses;
+  grpc_lb_addresses *lb_addresses;
 } ares_dns_resolver;
 
 static void dns_ares_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
@@ -109,6 +111,9 @@ static void dns_ares_shutdown_locked(grpc_exec_ctx *exec_ctx,
   if (r->have_retry_timer) {
     grpc_timer_cancel(exec_ctx, &r->retry_timer);
   }
+  if (r->pending_request != NULL) {
+    grpc_cancel_ares_request(exec_ctx, r->pending_request);
+  }
   if (r->next_completion != NULL) {
     *r->target_result = NULL;
     grpc_closure_sched(
@@ -145,19 +150,11 @@ static void dns_ares_on_resolved_locked(grpc_exec_ctx *exec_ctx, void *arg,
   grpc_channel_args *result = NULL;
   GPR_ASSERT(r->resolving);
   r->resolving = false;
-  if (r->addresses != NULL) {
-    grpc_lb_addresses *addresses = grpc_lb_addresses_create(
-        r->addresses->naddrs, NULL /* user_data_vtable */);
-    for (size_t i = 0; i < r->addresses->naddrs; ++i) {
-      grpc_lb_addresses_set_address(
-          addresses, i, &r->addresses->addrs[i].addr,
-          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);
+  r->pending_request = NULL;
+  if (r->lb_addresses != NULL) {
+    grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(r->lb_addresses);
     result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
-    grpc_resolved_addresses_destroy(r->addresses);
-    grpc_lb_addresses_destroy(exec_ctx, addresses);
+    grpc_lb_addresses_destroy(exec_ctx, r->lb_addresses);
   } else {
     const char *msg = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
@@ -209,10 +206,11 @@ static void dns_ares_start_resolving_locked(grpc_exec_ctx *exec_ctx,
   GRPC_RESOLVER_REF(&r->base, "dns-resolving");
   GPR_ASSERT(!r->resolving);
   r->resolving = true;
-  r->addresses = NULL;
-  grpc_dns_lookup_ares(exec_ctx, r->dns_server, r->name_to_resolve,
-                       r->default_port, r->interested_parties,
-                       &r->dns_ares_on_resolved_locked, &r->addresses);
+  r->lb_addresses = NULL;
+  r->pending_request = grpc_dns_lookup_ares(
+      exec_ctx, r->dns_server, r->name_to_resolve, r->default_port,
+      r->interested_parties, &r->dns_ares_on_resolved_locked, &r->lb_addresses,
+      true /* check_grpclb */);
 }
 
 static void dns_ares_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
@@ -222,6 +220,7 @@ static void dns_ares_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
     *r->target_result = r->resolved_result == NULL
                             ? NULL
                             : grpc_channel_args_copy(r->resolved_result);
+    gpr_log(GPR_DEBUG, "dns_ares_maybe_finish_next_locked");
     grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
     r->published_version = r->resolved_version;
@@ -245,10 +244,10 @@ static void dns_ares_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
 static grpc_resolver *dns_ares_create(grpc_exec_ctx *exec_ctx,
                                       grpc_resolver_args *args,
                                       const char *default_port) {
-  // Get name from args.
+  /* Get name from args. */
   const char *path = args->uri->path;
   if (path[0] == '/') ++path;
-  // Create resolver.
+  /* Create resolver. */
   ares_dns_resolver *r = gpr_zalloc(sizeof(ares_dns_resolver));
   grpc_resolver_init(&r->base, &dns_ares_resolver_vtable, args->combiner);
   if (0 != strcmp(args->uri->authority, "")) {
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
index ff3904e2520cfa9fbacb376f68c0dcc56219ad57..eb1a8ab011ced991838823bf9decab525eb5b064 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -47,5 +47,9 @@ grpc_error *grpc_ares_ev_driver_create(grpc_ares_ev_driver **ev_driver,
    of ARES_ECANCELLED. */
 void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver);
 
+/* Shutdown all the grpc_fds used by \a ev_driver */
+void grpc_ares_ev_driver_shutdown(grpc_exec_ctx *exec_ctx,
+                                  grpc_ares_ev_driver *ev_driver);
+
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H \
           */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
index 03ce3036162766eede2315bd32f75237de7db7b3..293e6b0252a6d47cbac48a1e3ef4d21ca00a07b1 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
@@ -99,9 +99,12 @@ static void fd_node_destroy(grpc_exec_ctx *exec_ctx, fd_node *fdn) {
   GPR_ASSERT(!fdn->writable_registered);
   gpr_mu_destroy(&fdn->mu);
   grpc_pollset_set_del_fd(exec_ctx, fdn->ev_driver->pollset_set, fdn->grpc_fd);
-  grpc_fd_shutdown(exec_ctx, fdn->grpc_fd,
-                   GRPC_ERROR_CREATE_FROM_STATIC_STRING("fd node destroyed"));
-  grpc_fd_orphan(exec_ctx, fdn->grpc_fd, NULL, NULL, "c-ares query finished");
+  /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up
+     immediately by another thread, and should not be closed by the following
+     grpc_fd_orphan. To prevent this fd from being closed by grpc_fd_orphan,
+     a fd pointer is provided. */
+  int fd;
+  grpc_fd_orphan(exec_ctx, fdn->grpc_fd, NULL, &fd, "c-ares query finished");
   gpr_free(fdn);
 }
 
@@ -140,6 +143,20 @@ void grpc_ares_ev_driver_destroy(grpc_ares_ev_driver *ev_driver) {
   grpc_ares_ev_driver_unref(ev_driver);
 }
 
+void grpc_ares_ev_driver_shutdown(grpc_exec_ctx *exec_ctx,
+                                  grpc_ares_ev_driver *ev_driver) {
+  gpr_mu_lock(&ev_driver->mu);
+  ev_driver->shutting_down = true;
+  fd_node *fn = ev_driver->fds;
+  while (fn != NULL) {
+    grpc_fd_shutdown(
+        exec_ctx, fn->grpc_fd,
+        GRPC_ERROR_CREATE_FROM_STATIC_STRING("grpc_ares_ev_driver_shutdown"));
+    fn = fn->next;
+  }
+  gpr_mu_unlock(&ev_driver->mu);
+}
+
 // Search fd in the fd_node list head. This is an O(n) search, the max possible
 // value of n is ARES_GETSOCK_MAXNUM (16). n is typically 1 - 2 in our tests.
 static fd_node *pop_fd_node(fd_node **head, int fd) {
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
index 4ee07e170af520816289fde2629b160733dcb373..153287c30e0b576aad7b1f0012b9b3374fabcfd3 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
@@ -33,6 +33,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include <nameser.h>
 
 #include "src/core/ext/filters/client_channel/parse_address.h"
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
@@ -45,20 +46,14 @@
 static gpr_once g_basic_init = GPR_ONCE_INIT;
 static gpr_mu g_init_mu;
 
-typedef struct grpc_ares_request {
+struct grpc_ares_request {
   /** indicates the DNS server to use, if specified */
   struct ares_addr_port_node dns_server_addr;
   /** following members are set in grpc_resolve_address_ares_impl */
-  /** host to resolve, parsed from the name to resolve */
-  char *host;
-  /** port to fill in sockaddr_in, parsed from the name to resolve */
-  char *port;
-  /** default port to use */
-  char *default_port;
   /** closure to call when the request completes */
   grpc_closure *on_done;
   /** the pointer to receive the resolved addresses */
-  grpc_resolved_addresses **addrs_out;
+  grpc_lb_addresses **lb_addrs_out;
   /** the evernt driver used by this request */
   grpc_ares_ev_driver *ev_driver;
   /** number of ongoing queries */
@@ -70,7 +65,19 @@ typedef struct grpc_ares_request {
   bool success;
   /** the errors explaining the request failure, set in on_done_cb */
   grpc_error *error;
-} grpc_ares_request;
+};
+
+typedef struct grpc_ares_hostbyname_request {
+  /** following members are set in create_hostbyname_request */
+  /** the top-level request instance */
+  grpc_ares_request *parent_request;
+  /** host to resolve, parsed from the name to resolve */
+  char *host;
+  /** port to fill in sockaddr_in, parsed from the name to resolve */
+  uint16_t port;
+  /** is it a grpclb address */
+  bool is_balancer;
+} grpc_ares_hostbyname_request;
 
 static void do_basic_init(void) { gpr_mu_init(&g_init_mu); }
 
@@ -83,6 +90,10 @@ static uint16_t strhtons(const char *port) {
   return htons((unsigned short)atoi(port));
 }
 
+static void grpc_ares_request_ref(grpc_ares_request *r) {
+  gpr_ref(&r->pending_queries);
+}
+
 static void grpc_ares_request_unref(grpc_exec_ctx *exec_ctx,
                                     grpc_ares_request *r) {
   /* If there are no pending queries, invoke on_done callback and destroy the
@@ -103,67 +114,95 @@ static void grpc_ares_request_unref(grpc_exec_ctx *exec_ctx,
     }
     gpr_mu_destroy(&r->mu);
     grpc_ares_ev_driver_destroy(r->ev_driver);
-    gpr_free(r->host);
-    gpr_free(r->port);
-    gpr_free(r->default_port);
     gpr_free(r);
   }
 }
 
-static void on_done_cb(void *arg, int status, int timeouts,
-                       struct hostent *hostent) {
-  grpc_ares_request *r = (grpc_ares_request *)arg;
+static grpc_ares_hostbyname_request *create_hostbyname_request(
+    grpc_ares_request *parent_request, char *host, uint16_t port,
+    bool is_balancer) {
+  grpc_ares_hostbyname_request *hr =
+      gpr_zalloc(sizeof(grpc_ares_hostbyname_request));
+  hr->parent_request = parent_request;
+  hr->host = gpr_strdup(host);
+  hr->port = port;
+  hr->is_balancer = is_balancer;
+  grpc_ares_request_ref(parent_request);
+  return hr;
+}
+
+static void destroy_hostbyname_request(grpc_exec_ctx *exec_ctx,
+                                       grpc_ares_hostbyname_request *hr) {
+  grpc_ares_request_unref(exec_ctx, hr->parent_request);
+  gpr_free(hr->host);
+  gpr_free(hr);
+}
+
+static void on_hostbyname_done_cb(void *arg, int status, int timeouts,
+                                  struct hostent *hostent) {
+  grpc_ares_hostbyname_request *hr = (grpc_ares_hostbyname_request *)arg;
+  grpc_ares_request *r = hr->parent_request;
   gpr_mu_lock(&r->mu);
   if (status == ARES_SUCCESS) {
     GRPC_ERROR_UNREF(r->error);
     r->error = GRPC_ERROR_NONE;
     r->success = true;
-    grpc_resolved_addresses **addresses = r->addrs_out;
-    if (*addresses == NULL) {
-      *addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
-      (*addresses)->naddrs = 0;
-      (*addresses)->addrs = NULL;
+    grpc_lb_addresses **lb_addresses = r->lb_addrs_out;
+    if (*lb_addresses == NULL) {
+      *lb_addresses = grpc_lb_addresses_create(0, NULL);
     }
-    size_t prev_naddr = (*addresses)->naddrs;
+    size_t prev_naddr = (*lb_addresses)->num_addresses;
     size_t i;
     for (i = 0; hostent->h_addr_list[i] != NULL; i++) {
     }
-    (*addresses)->naddrs += i;
-    (*addresses)->addrs =
-        gpr_realloc((*addresses)->addrs,
-                    sizeof(grpc_resolved_address) * (*addresses)->naddrs);
-    for (i = prev_naddr; i < (*addresses)->naddrs; i++) {
-      memset(&(*addresses)->addrs[i], 0, sizeof(grpc_resolved_address));
-      if (hostent->h_addrtype == AF_INET6) {
-        (*addresses)->addrs[i].len = sizeof(struct sockaddr_in6);
-        struct sockaddr_in6 *addr =
-            (struct sockaddr_in6 *)&(*addresses)->addrs[i].addr;
-        addr->sin6_family = (sa_family_t)hostent->h_addrtype;
-        addr->sin6_port = strhtons(r->port);
-
-        char output[INET6_ADDRSTRLEN];
-        memcpy(&addr->sin6_addr, hostent->h_addr_list[i - prev_naddr],
-               sizeof(struct in6_addr));
-        ares_inet_ntop(AF_INET6, &addr->sin6_addr, output, INET6_ADDRSTRLEN);
-        gpr_log(GPR_DEBUG,
-                "c-ares resolver gets a AF_INET6 result: \n"
-                "  addr: %s\n  port: %s\n  sin6_scope_id: %d\n",
-                output, r->port, addr->sin6_scope_id);
-      } else {
-        (*addresses)->addrs[i].len = sizeof(struct sockaddr_in);
-        struct sockaddr_in *addr =
-            (struct sockaddr_in *)&(*addresses)->addrs[i].addr;
-        memcpy(&addr->sin_addr, hostent->h_addr_list[i - prev_naddr],
-               sizeof(struct in_addr));
-        addr->sin_family = (sa_family_t)hostent->h_addrtype;
-        addr->sin_port = strhtons(r->port);
-
-        char output[INET_ADDRSTRLEN];
-        ares_inet_ntop(AF_INET, &addr->sin_addr, output, INET_ADDRSTRLEN);
-        gpr_log(GPR_DEBUG,
-                "c-ares resolver gets a AF_INET result: \n"
-                "  addr: %s\n  port: %s\n",
-                output, r->port);
+    (*lb_addresses)->num_addresses += i;
+    (*lb_addresses)->addresses =
+        gpr_realloc((*lb_addresses)->addresses,
+                    sizeof(grpc_lb_address) * (*lb_addresses)->num_addresses);
+    for (i = prev_naddr; i < (*lb_addresses)->num_addresses; i++) {
+      switch (hostent->h_addrtype) {
+        case AF_INET6: {
+          size_t addr_len = sizeof(struct sockaddr_in6);
+          struct sockaddr_in6 addr;
+          memset(&addr, 0, addr_len);
+          memcpy(&addr.sin6_addr, hostent->h_addr_list[i - prev_naddr],
+                 sizeof(struct in6_addr));
+          addr.sin6_family = (sa_family_t)hostent->h_addrtype;
+          addr.sin6_port = hr->port;
+          grpc_lb_addresses_set_address(
+              *lb_addresses, i, &addr, addr_len,
+              hr->is_balancer /* is_balancer */,
+              hr->is_balancer ? strdup(hr->host) : NULL /* balancer_name */,
+              NULL /* user_data */);
+          char output[INET6_ADDRSTRLEN];
+          ares_inet_ntop(AF_INET6, &addr.sin6_addr, output, INET6_ADDRSTRLEN);
+          gpr_log(GPR_DEBUG,
+                  "c-ares resolver gets a AF_INET6 result: \n"
+                  "  addr: %s\n  port: %d\n  sin6_scope_id: %d\n",
+                  output, ntohs(hr->port), addr.sin6_scope_id);
+          break;
+        }
+        case AF_INET: {
+          size_t addr_len = sizeof(struct sockaddr_in);
+          struct sockaddr_in addr;
+          memset(&addr, 0, addr_len);
+          memcpy(&addr.sin_addr, hostent->h_addr_list[i - prev_naddr],
+                 sizeof(struct in_addr));
+          addr.sin_family = (sa_family_t)hostent->h_addrtype;
+          addr.sin_port = hr->port;
+          grpc_lb_addresses_set_address(
+              *lb_addresses, i, &addr, addr_len,
+              hr->is_balancer /* is_balancer */,
+              hr->is_balancer ? strdup(hr->host) : NULL /* balancer_name */,
+              NULL /* user_data */);
+          char output[INET_ADDRSTRLEN];
+          ares_inet_ntop(AF_INET, &addr.sin_addr, output, INET_ADDRSTRLEN);
+          gpr_log(GPR_DEBUG,
+                  "c-ares resolver gets a AF_INET result: \n"
+                  "  addr: %s\n  port: %d\n",
+                  output, ntohs(hr->port));
+          break;
+        }
       }
     }
   } else if (!r->success) {
@@ -179,14 +218,58 @@ static void on_done_cb(void *arg, int status, int timeouts,
     }
   }
   gpr_mu_unlock(&r->mu);
-  grpc_ares_request_unref(NULL, r);
+  destroy_hostbyname_request(NULL, hr);
+}
+
+static void on_srv_query_done_cb(void *arg, int status, int timeouts,
+                                 unsigned char *abuf, int alen) {
+  grpc_ares_request *r = (grpc_ares_request *)arg;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  gpr_log(GPR_DEBUG, "on_query_srv_done_cb");
+  if (status == ARES_SUCCESS) {
+    gpr_log(GPR_DEBUG, "on_query_srv_done_cb ARES_SUCCESS");
+    struct ares_srv_reply *reply;
+    const int parse_status = ares_parse_srv_reply(abuf, alen, &reply);
+    if (parse_status == ARES_SUCCESS) {
+      ares_channel *channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
+      for (struct ares_srv_reply *srv_it = reply; srv_it != NULL;
+           srv_it = srv_it->next) {
+        if (grpc_ipv6_loopback_available()) {
+          grpc_ares_hostbyname_request *hr = create_hostbyname_request(
+              r, srv_it->host, srv_it->port, true /* is_balancer */);
+          ares_gethostbyname(*channel, hr->host, AF_INET6,
+                             on_hostbyname_done_cb, hr);
+        }
+        grpc_ares_hostbyname_request *hr = create_hostbyname_request(
+            r, srv_it->host, srv_it->port, true /* is_balancer */);
+        ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb,
+                           hr);
+        grpc_ares_ev_driver_start(&exec_ctx, r->ev_driver);
+      }
+    }
+    if (reply != NULL) {
+      ares_free_data(reply);
+    }
+  } else if (!r->success) {
+    char *error_msg;
+    gpr_asprintf(&error_msg, "C-ares status is not ARES_SUCCESS: %s",
+                 ares_strerror(status));
+    grpc_error *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
+    gpr_free(error_msg);
+    if (r->error == GRPC_ERROR_NONE) {
+      r->error = error;
+    } else {
+      r->error = grpc_error_add_child(error, r->error);
+    }
+  }
+  grpc_ares_request_unref(&exec_ctx, r);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
-void grpc_dns_lookup_ares(grpc_exec_ctx *exec_ctx, const char *dns_server,
-                          const char *name, const char *default_port,
-                          grpc_pollset_set *interested_parties,
-                          grpc_closure *on_done,
-                          grpc_resolved_addresses **addrs) {
+static grpc_ares_request *grpc_dns_lookup_ares_impl(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb) {
   grpc_error *error = GRPC_ERROR_NONE;
   /* TODO(zyc): Enable tracing after #9603 is checked in */
   /* if (grpc_dns_trace) {
@@ -221,10 +304,7 @@ void grpc_dns_lookup_ares(grpc_exec_ctx *exec_ctx, const char *dns_server,
   gpr_mu_init(&r->mu);
   r->ev_driver = ev_driver;
   r->on_done = on_done;
-  r->addrs_out = addrs;
-  r->default_port = gpr_strdup(default_port);
-  r->port = port;
-  r->host = host;
+  r->lb_addrs_out = addrs;
   r->success = false;
   r->error = GRPC_ERROR_NONE;
   ares_channel *channel = grpc_ares_ev_driver_get_channel(r->ev_driver);
@@ -248,6 +328,7 @@ void grpc_dns_lookup_ares(grpc_exec_ctx *exec_ctx, const char *dns_server,
       error = grpc_error_set_str(
           GRPC_ERROR_CREATE_FROM_STATIC_STRING("cannot parse authority"),
           GRPC_ERROR_STR_TARGET_ADDRESS, grpc_slice_from_copied_string(name));
+      gpr_free(r);
       goto error_cleanup;
     }
     int status = ares_set_servers_ports(*channel, &r->dns_server_addr);
@@ -257,41 +338,55 @@ void grpc_dns_lookup_ares(grpc_exec_ctx *exec_ctx, const char *dns_server,
                    ares_strerror(status));
       error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
       gpr_free(error_msg);
+      gpr_free(r);
       goto error_cleanup;
     }
   }
   // An extra reference is put here to avoid destroying the request in
   // on_done_cb before calling grpc_ares_ev_driver_start.
-  gpr_ref_init(&r->pending_queries, 2);
+  gpr_ref_init(&r->pending_queries, 1);
   if (grpc_ipv6_loopback_available()) {
-    gpr_ref(&r->pending_queries);
-    ares_gethostbyname(*channel, r->host, AF_INET6, on_done_cb, r);
+    grpc_ares_hostbyname_request *hr = create_hostbyname_request(
+        r, host, strhtons(port), false /* is_balancer */);
+    ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_cb, hr);
+  }
+  grpc_ares_hostbyname_request *hr = create_hostbyname_request(
+      r, host, strhtons(port), false /* is_balancer */);
+  ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_cb, hr);
+  if (check_grpclb) {
+    /* Query the SRV record */
+    grpc_ares_request_ref(r);
+    char *service_name;
+    gpr_asprintf(&service_name, "_grpclb._tcp.%s", host);
+    ares_query(*channel, service_name, ns_c_in, ns_t_srv, on_srv_query_done_cb,
+               r);
+    gpr_free(service_name);
   }
-  ares_gethostbyname(*channel, r->host, AF_INET, on_done_cb, r);
   /* TODO(zyc): Handle CNAME records here. */
   grpc_ares_ev_driver_start(exec_ctx, r->ev_driver);
   grpc_ares_request_unref(exec_ctx, r);
-  return;
+  gpr_free(host);
+  gpr_free(port);
+  return r;
 
 error_cleanup:
   grpc_closure_sched(exec_ctx, on_done, error);
   gpr_free(host);
   gpr_free(port);
+  return NULL;
 }
 
-void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx, const char *name,
-                                    const char *default_port,
-                                    grpc_pollset_set *interested_parties,
-                                    grpc_closure *on_done,
-                                    grpc_resolved_addresses **addrs) {
-  grpc_dns_lookup_ares(exec_ctx, NULL /* dns_server */, name, default_port,
-                       interested_parties, on_done, addrs);
-}
+grpc_ares_request *(*grpc_dns_lookup_ares)(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **addrs,
+    bool check_grpclb) = grpc_dns_lookup_ares_impl;
 
-void (*grpc_resolve_address_ares)(
-    grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
-    grpc_pollset_set *interested_parties, grpc_closure *on_done,
-    grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl;
+void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx, grpc_ares_request *r) {
+  if (grpc_dns_lookup_ares == grpc_dns_lookup_ares_impl) {
+    grpc_ares_ev_driver_shutdown(exec_ctx, r->ev_driver);
+  }
+}
 
 grpc_error *grpc_ares_init(void) {
   gpr_once_init(&g_basic_init, do_basic_init);
@@ -316,4 +411,66 @@ void grpc_ares_cleanup(void) {
   gpr_mu_unlock(&g_init_mu);
 }
 
+/*
+ * grpc_resolve_address_ares related structs and functions
+ */
+
+typedef struct grpc_resolve_address_ares_request {
+  /** the pointer to receive the resolved addresses */
+  grpc_resolved_addresses **addrs_out;
+  /** currently resolving lb addresses */
+  grpc_lb_addresses *lb_addrs;
+  /** closure to call when the resolve_address_ares request completes */
+  grpc_closure *on_resolve_address_done;
+  /** a closure wrapping on_dns_lookup_done_cb, which should be invoked when the
+      grpc_dns_lookup_ares operation is done. */
+  grpc_closure on_dns_lookup_done;
+} grpc_resolve_address_ares_request;
+
+static void on_dns_lookup_done_cb(grpc_exec_ctx *exec_ctx, void *arg,
+                                  grpc_error *error) {
+  grpc_resolve_address_ares_request *r =
+      (grpc_resolve_address_ares_request *)arg;
+  grpc_resolved_addresses **resolved_addresses = r->addrs_out;
+  if (r->lb_addrs == NULL || r->lb_addrs->num_addresses == 0) {
+    *resolved_addresses = NULL;
+  } else {
+    *resolved_addresses = gpr_zalloc(sizeof(grpc_resolved_addresses));
+    (*resolved_addresses)->naddrs = r->lb_addrs->num_addresses;
+    (*resolved_addresses)->addrs = gpr_zalloc(sizeof(grpc_resolved_address) *
+                                              (*resolved_addresses)->naddrs);
+    for (size_t i = 0; i < (*resolved_addresses)->naddrs; i++) {
+      GPR_ASSERT(!r->lb_addrs->addresses[i].is_balancer);
+      memcpy(&(*resolved_addresses)->addrs[i],
+             &r->lb_addrs->addresses[i].address, sizeof(grpc_resolved_address));
+    }
+  }
+  grpc_closure_sched(exec_ctx, r->on_resolve_address_done,
+                     GRPC_ERROR_REF(error));
+  grpc_lb_addresses_destroy(exec_ctx, r->lb_addrs);
+  gpr_free(r);
+}
+
+static void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx,
+                                           const char *name,
+                                           const char *default_port,
+                                           grpc_pollset_set *interested_parties,
+                                           grpc_closure *on_done,
+                                           grpc_resolved_addresses **addrs) {
+  grpc_resolve_address_ares_request *r =
+      gpr_zalloc(sizeof(grpc_resolve_address_ares_request));
+  r->addrs_out = addrs;
+  r->on_resolve_address_done = on_done;
+  grpc_closure_init(&r->on_dns_lookup_done, on_dns_lookup_done_cb, r,
+                    grpc_schedule_on_exec_ctx);
+  grpc_dns_lookup_ares(exec_ctx, NULL /* dns_server */, name, default_port,
+                       interested_parties, &r->on_dns_lookup_done, &r->lb_addrs,
+                       false /* check_grpclb */);
+}
+
+void (*grpc_resolve_address_ares)(
+    grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
+    grpc_pollset_set *interested_parties, grpc_closure *on_done,
+    grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl;
+
 #endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index 08efeea04a92ab0beb0992397ca8cfd7082ce329..5d2d6c993bd3ff8cdb16ebb6ea54f3682600dbc3 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -19,11 +19,14 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H
 
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
+typedef struct grpc_ares_request grpc_ares_request;
+
 /* Asynchronously resolve addr. Use \a default_port if a port isn't designated
    in addr, otherwise use the port in addr. grpc_ares_init() must be called at
    least once before this function. \a on_done may be called directly in this
@@ -36,11 +39,21 @@ extern void (*grpc_resolve_address_ares)(grpc_exec_ctx *exec_ctx,
                                          grpc_closure *on_done,
                                          grpc_resolved_addresses **addresses);
 
-void grpc_dns_lookup_ares(grpc_exec_ctx *exec_ctx, const char *dns_server,
-                          const char *addr, const char *default_port,
-                          grpc_pollset_set *interested_parties,
-                          grpc_closure *on_done,
-                          grpc_resolved_addresses **addresses);
+/* Asynchronously resolve addr. It will try to resolve grpclb SRV records in
+  addition to the normal address records. For normal address records, it uses
+  \a default_port if a port isn't designated in \a addr, otherwise it uses the
+  port in \a addr. grpc_ares_init() must be called at least once before this
+  function. \a on_done may be called directly in this function without being
+  scheduled with \a exec_ctx, it must not try to acquire locks that are being
+  held by the caller. */
+extern grpc_ares_request *(*grpc_dns_lookup_ares)(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *addr,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **addresses, bool check_grpclb);
+
+/* Cancel the pending grpc_ares_request \a request */
+void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx,
+                              grpc_ares_request *request);
 
 /* Initialize gRPC ares wrapper. Must be called at least once before
    grpc_resolve_address_ares(). */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c15e3bdf5ccdef67e9d9bc1da4b77997c564033
--- /dev/null
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright 2017, 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.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#if GRPC_ARES != 1 || defined(GRPC_UV)
+
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+
+struct grpc_ares_request {
+  char val;
+};
+
+static grpc_ares_request *grpc_dns_lookup_ares_impl(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **addrs, bool check_grpclb) {
+  return NULL;
+}
+
+grpc_ares_request *(*grpc_dns_lookup_ares)(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *name,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **addrs,
+    bool check_grpclb) = grpc_dns_lookup_ares_impl;
+
+void grpc_cancel_ares_request(grpc_exec_ctx *exec_ctx, grpc_ares_request *r) {}
+
+grpc_error *grpc_ares_init(void) { return GRPC_ERROR_NONE; }
+
+void grpc_ares_cleanup(void) {}
+
+static void grpc_resolve_address_ares_impl(grpc_exec_ctx *exec_ctx,
+                                           const char *name,
+                                           const char *default_port,
+                                           grpc_pollset_set *interested_parties,
+                                           grpc_closure *on_done,
+                                           grpc_resolved_addresses **addrs) {}
+
+void (*grpc_resolve_address_ares)(
+    grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
+    grpc_pollset_set *interested_parties, grpc_closure *on_done,
+    grpc_resolved_addresses **addrs) = grpc_resolve_address_ares_impl;
+
+#endif /* GRPC_ARES != 1 || defined(GRPC_UV) */
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c
index 328b5b297c103788b2e659303e63996b90bda5fe..a58218bae39a93003943e27cc3c086326da8eb3b 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.c
+++ b/src/core/lib/iomgr/ev_epollsig_linux.c
@@ -1032,7 +1032,10 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
        unhappy. */
     PI_UNREF(exec_ctx, unref_pi, "fd_orphan");
   }
-  GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error));
+  if (error != GRPC_ERROR_NONE) {
+    const char *msg = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "fd_orphan: %s", msg);
+  }
   GRPC_ERROR_UNREF(error);
 }
 
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 1a5c537d1fd7673a83c235e7b2857e0e4834d70b..e3b2ffaf9ed16f6d9721a1925df24fb8f8f36cc7 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -287,6 +287,7 @@ CORE_SOURCE_FILES = [
   'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
   'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
   'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+  'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c',
   'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
   'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
   'src/core/ext/filters/load_reporting/load_reporting.c',
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
index 99fccd055d7ce0c4f438cb51b2d6759133241128..14076281984dcd6953e929fc3ca5271801676a57 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
@@ -21,7 +21,9 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/resolver.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/combiner.h"
@@ -55,6 +57,26 @@ static void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
   grpc_closure_sched(exec_ctx, on_done, error);
 }
 
+static grpc_ares_request *my_dns_lookup_ares(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *addr,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **lb_addrs, bool check_grpclb) {
+  gpr_mu_lock(&g_mu);
+  GPR_ASSERT(0 == strcmp("test", addr));
+  grpc_error *error = GRPC_ERROR_NONE;
+  if (g_fail_resolution) {
+    g_fail_resolution = false;
+    gpr_mu_unlock(&g_mu);
+    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure");
+  } else {
+    gpr_mu_unlock(&g_mu);
+    *lb_addrs = grpc_lb_addresses_create(1, NULL);
+    grpc_lb_addresses_set_address(*lb_addrs, 0, NULL, 0, false, NULL, NULL);
+  }
+  grpc_closure_sched(exec_ctx, on_done, error);
+  return NULL;
+}
+
 static grpc_resolver *create_resolver(grpc_exec_ctx *exec_ctx,
                                       const char *name) {
   grpc_resolver_factory *factory = grpc_resolver_factory_lookup("dns");
@@ -125,6 +147,7 @@ int main(int argc, char **argv) {
   gpr_mu_init(&g_mu);
   g_combiner = grpc_combiner_create(NULL);
   grpc_resolve_address = my_resolve_address;
+  grpc_dns_lookup_ares = my_dns_lookup_ares;
   grpc_channel_args *result = (grpc_channel_args *)1;
 
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.c b/test/core/client_channel/resolvers/dns_resolver_test.c
index 8fc8bde438ca7b76a7efcb426174649a50a8e635..877f8d9e88409f3078a0ecdcf2cb073f4f462394 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_test.c
@@ -20,6 +20,7 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver_registry.h"
 #include "src/core/lib/iomgr/combiner.h"
 #include "test/core/util/test_config.h"
@@ -73,7 +74,11 @@ int main(int argc, char **argv) {
   test_succeeds(dns, "dns:10.2.1.1");
   test_succeeds(dns, "dns:10.2.1.1:1234");
   test_succeeds(dns, "ipv4:www.google.com");
-  test_fails(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
+  if (grpc_resolve_address == grpc_resolve_address_ares) {
+    test_succeeds(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
+  } else {
+    test_fails(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
+  }
 
   grpc_resolver_factory_unref(dns);
   {
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index 8a97d01f462ec9757c4278e51ffa37ea3bfae979..d742c3d838d91fcebe27d7b2e04c21e3fe3454ce 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -24,6 +24,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -362,6 +364,7 @@ typedef struct addr_req {
   char *addr;
   grpc_closure *on_done;
   grpc_resolved_addresses **addrs;
+  grpc_lb_addresses **lb_addrs;
 } addr_req;
 
 static void finish_resolve(grpc_exec_ctx *exec_ctx, void *arg,
@@ -369,11 +372,17 @@ static void finish_resolve(grpc_exec_ctx *exec_ctx, void *arg,
   addr_req *r = arg;
 
   if (error == GRPC_ERROR_NONE && 0 == strcmp(r->addr, "server")) {
-    grpc_resolved_addresses *addrs = gpr_malloc(sizeof(*addrs));
-    addrs->naddrs = 1;
-    addrs->addrs = gpr_malloc(sizeof(*addrs->addrs));
-    addrs->addrs[0].len = 0;
-    *r->addrs = addrs;
+    if (r->addrs != NULL) {
+      grpc_resolved_addresses *addrs = gpr_malloc(sizeof(*addrs));
+      addrs->naddrs = 1;
+      addrs->addrs = gpr_malloc(sizeof(*addrs->addrs));
+      addrs->addrs[0].len = 0;
+      *r->addrs = addrs;
+    } else if (r->lb_addrs != NULL) {
+      grpc_lb_addresses *lb_addrs = grpc_lb_addresses_create(1, NULL);
+      grpc_lb_addresses_set_address(lb_addrs, 0, NULL, 0, NULL, NULL, NULL);
+      *r->lb_addrs = lb_addrs;
+    }
     grpc_closure_sched(exec_ctx, r->on_done, GRPC_ERROR_NONE);
   } else {
     grpc_closure_sched(exec_ctx, r->on_done,
@@ -394,11 +403,29 @@ void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
   r->addr = gpr_strdup(addr);
   r->on_done = on_done;
   r->addrs = addresses;
+  r->lb_addrs = NULL;
+  grpc_timer_init(
+      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),
+      grpc_closure_create(finish_resolve, r, grpc_schedule_on_exec_ctx),
+      gpr_now(GPR_CLOCK_MONOTONIC));
+}
+
+grpc_ares_request *my_dns_lookup_ares(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *addr,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **lb_addrs, bool check_grpclb) {
+  addr_req *r = gpr_malloc(sizeof(*r));
+  r->addr = gpr_strdup(addr);
+  r->on_done = on_done;
+  r->addrs = NULL;
+  r->lb_addrs = lb_addrs;
   grpc_timer_init(
       exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                                         gpr_time_from_seconds(1, GPR_TIMESPAN)),
       grpc_closure_create(finish_resolve, r, grpc_schedule_on_exec_ctx),
       gpr_now(GPR_CLOCK_MONOTONIC));
+  return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -710,6 +737,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   grpc_init();
   grpc_timer_manager_set_threading(false);
   grpc_resolve_address = my_resolve_address;
+  grpc_dns_lookup_ares = my_dns_lookup_ares;
 
   GPR_ASSERT(g_channel == NULL);
   GPR_ASSERT(g_server == NULL);
diff --git a/test/core/end2end/goaway_server_test.c b/test/core/end2end/goaway_server_test.c
index 49378665a03593beff78517aeedb27ae127b4e80..91a377e6b9b3fe679ca4581822616479cc9ba31e 100644
--- a/test/core/end2end/goaway_server_test.c
+++ b/test/core/end2end/goaway_server_test.c
@@ -27,6 +27,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <string.h>
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -43,6 +45,11 @@ static void (*iomgr_resolve_address)(grpc_exec_ctx *exec_ctx, const char *addr,
                                      grpc_closure *on_done,
                                      grpc_resolved_addresses **addresses);
 
+static grpc_ares_request *(*iomgr_dns_lookup_ares)(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *addr,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **addresses, bool check_grpclb);
+
 static void set_resolve_port(int port) {
   gpr_mu_lock(&g_mu);
   g_resolve_port = port;
@@ -80,6 +87,36 @@ static void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
   grpc_closure_sched(exec_ctx, on_done, error);
 }
 
+static grpc_ares_request *my_dns_lookup_ares(
+    grpc_exec_ctx *exec_ctx, const char *dns_server, const char *addr,
+    const char *default_port, grpc_pollset_set *interested_parties,
+    grpc_closure *on_done, grpc_lb_addresses **lb_addrs, bool check_grpclb) {
+  if (0 != strcmp(addr, "test")) {
+    return iomgr_dns_lookup_ares(exec_ctx, dns_server, addr, default_port,
+                                 interested_parties, on_done, lb_addrs,
+                                 check_grpclb);
+  }
+
+  grpc_error *error = GRPC_ERROR_NONE;
+  gpr_mu_lock(&g_mu);
+  if (g_resolve_port < 0) {
+    gpr_mu_unlock(&g_mu);
+    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Failure");
+  } else {
+    *lb_addrs = grpc_lb_addresses_create(1, NULL);
+    struct sockaddr_in *sa = gpr_zalloc(sizeof(struct sockaddr_in));
+    sa->sin_family = AF_INET;
+    sa->sin_addr.s_addr = htonl(0x7f000001);
+    sa->sin_port = htons((uint16_t)g_resolve_port);
+    grpc_lb_addresses_set_address(*lb_addrs, 0, sa, sizeof(*sa), false, NULL,
+                                  NULL);
+    gpr_free(sa);
+    gpr_mu_unlock(&g_mu);
+  }
+  grpc_closure_sched(exec_ctx, on_done, error);
+  return NULL;
+}
+
 int main(int argc, char **argv) {
   grpc_completion_queue *cq;
   cq_verifier *cqv;
@@ -91,7 +128,9 @@ int main(int argc, char **argv) {
   gpr_mu_init(&g_mu);
   grpc_init();
   iomgr_resolve_address = grpc_resolve_address;
+  iomgr_dns_lookup_ares = grpc_dns_lookup_ares;
   grpc_resolve_address = my_resolve_address;
+  grpc_dns_lookup_ares = my_dns_lookup_ares;
 
   int was_cancelled1;
   int was_cancelled2;
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index 89e0aca79cd940c2c598b340171c64b902e5214f..e5a2ecd5171bbebdbf5ea9827988df1055403b0d 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -92,6 +92,7 @@ void grpc_free_port_using_server(int port) {
                                        grpc_schedule_on_exec_ctx),
                    &rsp);
   grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_exec_ctx_flush(&exec_ctx);
   gpr_mu_lock(pr.mu);
   while (!pr.done) {
     grpc_pollset_worker *worker = NULL;
@@ -224,6 +225,7 @@ int grpc_pick_port_using_server(void) {
       grpc_closure_create(got_port_from_server, &pr, grpc_schedule_on_exec_ctx),
       &pr.response);
   grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_exec_ctx_flush(&exec_ctx);
   gpr_mu_lock(pr.mu);
   while (pr.port == -1) {
     grpc_pollset_worker *worker = NULL;
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 98ed72a6adc31c1f966fbbad9afb8fa6e72d6f45..fe11fa059332b0b4544b3f2f9918cfc27554e335 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -948,6 +948,7 @@ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \
 src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
 src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
 src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h \
+src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c \
 src/core/ext/filters/client_channel/resolver/dns/native/README.md \
 src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c \
 src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 8835118e3a2a8e6be8c153ade6a0a7f9ee7913f4..1e32527c6bfac3f9ee92f8d320ec7b24d2edd91e 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -8526,7 +8526,8 @@
       "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", 
       "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c", 
       "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c", 
-      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h", 
+      "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c"
     ], 
     "third_party": false, 
     "type": "filegroup"
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index d4bdaa233ea0efbe27cec9aa717be00e0d74f807..de2f7e680e77f84042de37e0149f157bb21850b7 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -974,6 +974,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 571837c3fd3c219c576529a05996b5fe9adf63b9..3f52415bfcb975febf05f1eabff19fb2878f9c13 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -679,6 +679,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\native</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 76770b04202be6c9a7f9cc3af214cd239823d5b2..b0ab4e48115074340e258b1c1e40adbec1d0f4ea 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -857,6 +857,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\sockaddr\sockaddr_resolver.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 92d9e37b3a3e8a9c9f0fda9515fc1579a1df3064..51cef73113e2193cf4968839c5b279daea2ebe43 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -556,6 +556,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.c">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper_fallback.c">
+      <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\native\dns_resolver.c">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\native</Filter>
     </ClCompile>