diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 3631d2fe1..59f673ad5 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -232,7 +232,7 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
 static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 #endif
 
-static soinfo __libdl_info("libdl.so", nullptr, 0);
+static soinfo __libdl_info("libdl.so", nullptr, 0, RTLD_GLOBAL);
 
 // This is used by the dynamic linker. Every process gets these symbols for free.
 soinfo* get_libdl_info() {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 37e01893f..bd05498b0 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -282,13 +282,13 @@ static void protect_data(int protection) {
   g_soinfo_links_allocator.protect_all(protection);
 }
 
-static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset) {
+static soinfo* soinfo_alloc(const char* name, struct stat* file_stat, off64_t file_offset, int rtld_flags) {
   if (strlen(name) >= SOINFO_NAME_LEN) {
     DL_ERR("library name \"%s\" too long", name);
     return nullptr;
   }
 
-  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset);
+  soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat, file_offset, rtld_flags);
 
   sonext->next = si;
   sonext = si;
@@ -453,7 +453,7 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name)
   return nullptr;
 }
 
-soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset) {
+soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags) {
   memset(this, 0, sizeof(*this));
 
   strlcpy(this->name, name, sizeof(this->name));
@@ -465,6 +465,8 @@ soinfo::soinfo(const char* name, const struct stat* file_stat, off64_t file_offs
     this->st_ino = file_stat->st_ino;
     this->file_offset = file_offset;
   }
+
+  this->rtld_flags = rtld_flags;
 }
 
 static unsigned elfhash(const char* _name) {
@@ -716,6 +718,10 @@ ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* start)
 
   ElfW(Sym)* s = nullptr;
   for (soinfo* si = start; (s == nullptr) && (si != nullptr); si = si->next) {
+    if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+      continue;
+    }
+
     s = soinfo_elf_lookup(si, elf_hash, name);
     if (s != nullptr) {
       *found = si;
@@ -806,7 +812,7 @@ static void for_each_dt_needed(const soinfo* si, F action) {
   }
 }
 
-static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) {
+static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
   int fd = -1;
   off64_t file_offset = 0;
   ScopedFd file_guard(-1);
@@ -851,7 +857,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl
     }
   }
 
-  if ((dlflags & RTLD_NOLOAD) != 0) {
+  if ((rtld_flags & RTLD_NOLOAD) != 0) {
     DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
     return nullptr;
   }
@@ -862,7 +868,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int dlfl
     return nullptr;
   }
 
-  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset);
+  soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat, file_offset, rtld_flags);
   if (si == nullptr) {
     return nullptr;
   }
@@ -894,7 +900,7 @@ static soinfo *find_loaded_library_by_name(const char* name) {
   return nullptr;
 }
 
-static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int dlflags, const android_dlextinfo* extinfo) {
+static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
 
   soinfo* si = find_loaded_library_by_name(name);
 
@@ -902,7 +908,7 @@ static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
   // of this fact is done by load_library.
   if (si == nullptr) {
     TRACE("[ '%s' has not been found by name.  Trying harder...]", name);
-    si = load_library(load_tasks, name, dlflags, extinfo);
+    si = load_library(load_tasks, name, rtld_flags, extinfo);
   }
 
   return si;
@@ -926,7 +932,7 @@ static bool is_recursive(soinfo* si, soinfo* parent) {
 }
 
 static bool find_libraries(const char* const library_names[], size_t library_names_size, soinfo* soinfos[],
-    soinfo* ld_preloads[], size_t ld_preloads_size, int dlflags, const android_dlextinfo* extinfo) {
+    soinfo* ld_preloads[], size_t ld_preloads_size, int rtld_flags, const android_dlextinfo* extinfo) {
   // Step 0: prepare.
   LoadTaskList load_tasks;
   for (size_t i = 0; i < library_names_size; ++i) {
@@ -952,7 +958,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam
 
   // Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
   for (LoadTask::unique_ptr task(load_tasks.pop_front()); task.get() != nullptr; task.reset(load_tasks.pop_front())) {
-    soinfo* si = find_library_internal(load_tasks, task->get_name(), dlflags, extinfo);
+    soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
     if (si == nullptr) {
       return false;
     }
@@ -997,7 +1003,7 @@ static bool find_libraries(const char* const library_names[], size_t library_nam
   return true;
 }
 
-static soinfo* find_library(const char* name, int dlflags, const android_dlextinfo* extinfo) {
+static soinfo* find_library(const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
   if (name == nullptr) {
     somain->ref_count++;
     return somain;
@@ -1005,7 +1011,7 @@ static soinfo* find_library(const char* name, int dlflags, const android_dlextin
 
   soinfo* si;
 
-  if (!find_libraries(&name, 1, &si, nullptr, 0, dlflags, extinfo)) {
+  if (!find_libraries(&name, 1, &si, nullptr, 0, rtld_flags, extinfo)) {
     return nullptr;
   }
 
@@ -1790,6 +1796,14 @@ off64_t soinfo::get_file_offset() {
   return 0;
 }
 
+int soinfo::get_rtld_flags() {
+  if (has_min_version(1)) {
+    return rtld_flags;
+  }
+
+  return 0;
+}
+
 // This is a return on get_children()/get_parents() if
 // 'this->flags' does not have FLAG_NEW_SOINFO set.
 static soinfo::soinfo_list_t g_empty_list;
@@ -2210,7 +2224,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) {
     return;
   }
 
-  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0);
+  soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0);
 
   si->phdr = reinterpret_cast<ElfW(Phdr)*>(reinterpret_cast<char*>(ehdr_vdso) + ehdr_vdso->e_phoff);
   si->phnum = ehdr_vdso->e_phnum;
@@ -2231,7 +2245,7 @@ static void add_vdso(KernelArgumentBlock& args __unused) {
 #else
 #define LINKER_PATH "/system/bin/linker"
 #endif
-static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0);
+static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr, 0, 0);
 
 /* gdb expects the linker to be in the debug shared object list.
  * Without this, gdb has trouble locating the linker's ".text"
@@ -2295,7 +2309,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
 
   INFO("[ android linker & debugger ]");
 
-  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0);
+  soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
   if (si == nullptr) {
     exit(EXIT_FAILURE);
   }
@@ -2370,7 +2384,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
   memset(needed_library_names, 0, sizeof(needed_library_names));
   needed_library_name_list.copy_to_array(needed_library_names, needed_libraries_count);
 
-  if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, 0, nullptr)) {
+  if (needed_libraries_count > 0 && !find_libraries(needed_library_names, needed_libraries_count, needed_library_si, g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr)) {
     __libc_format_fd(2, "CANNOT LINK EXECUTABLE DEPENDENCIES: %s\n", linker_get_error_buffer());
     exit(EXIT_FAILURE);
   }
@@ -2483,7 +2497,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
   ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
   ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
 
-  soinfo linker_so("[dynamic linker]", nullptr, 0);
+  soinfo linker_so("[dynamic linker]", nullptr, 0, 0);
 
   // If the linker is not acting as PT_INTERP entry_point is equal to
   // _start. Which means that the linker is running as an executable and
diff --git a/linker/linker.h b/linker/linker.h
index 3b140ac24..ef2fbcd6c 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -199,7 +199,7 @@ struct soinfo {
 #endif
   bool has_DT_SYMBOLIC;
 
-  soinfo(const char* name, const struct stat* file_stat, off64_t file_offset);
+  soinfo(const char* name, const struct stat* file_stat, off64_t file_offset, int rtld_flags);
 
   void CallConstructors();
   void CallDestructors();
@@ -214,6 +214,8 @@ struct soinfo {
   dev_t get_st_dev();
   off64_t get_file_offset();
 
+  int get_rtld_flags();
+
   soinfo_list_t& get_children();
   soinfo_list_t& get_parents();
 
@@ -246,6 +248,7 @@ struct soinfo {
 
   // version >= 1
   off64_t file_offset;
+  int rtld_flags;
 };
 
 extern soinfo* get_libdl_info();
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 9c9fbdd12..a55b36420 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -202,6 +202,42 @@ TEST(dlfcn, dlopen_check_order) {
   dlclose(handle);
 }
 
+TEST(dlfcn, dlopen_check_rtld_local) {
+  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym == nullptr);
+
+  // implicit RTLD_LOCAL
+  void* handle = dlopen("libtest_simple.so", RTLD_NOW);
+  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
+  sym = dlsym(handle, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym != nullptr);
+  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
+  dlclose(handle);
+
+  // explicit RTLD_LOCAL
+  handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_LOCAL);
+  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym == nullptr);
+  ASSERT_SUBSTR("undefined symbol: dlopen_testlib_simple_func", dlerror());
+  sym = dlsym(handle, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym != nullptr);
+  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
+  dlclose(handle);
+}
+
+TEST(dlfcn, dlopen_check_rtld_global) {
+  void* sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym == nullptr);
+
+  void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_GLOBAL);
+  sym = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
+  ASSERT_TRUE(sym != nullptr) << dlerror();
+  ASSERT_TRUE(reinterpret_cast<bool (*)(void)>(sym)());
+  dlclose(handle);
+}
+
 // libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
 // libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so ->
 // libtest_with_dependency_loop_a.so
diff --git a/tests/libs/dlopen_testlib_simple.cpp b/tests/libs/dlopen_testlib_simple.cpp
index afe54b4c0..06253e1f4 100644
--- a/tests/libs/dlopen_testlib_simple.cpp
+++ b/tests/libs/dlopen_testlib_simple.cpp
@@ -18,6 +18,6 @@
 
 uint32_t dlopen_testlib_taxicab_number = 1729;
 
-bool dlopen_testlib_simple_func() {
+extern "C" bool dlopen_testlib_simple_func() {
   return true;
 }