It's not clearly mentioned but I assume you are talking about ARM architecture. ***“32-bit Android OS”*** means a 32-bit kernel and the collection of ELF binaries and libraries which are compiled to run on 32-bit processor. This middleware stack particularly includes `app_process` binary which runs with name `zygote` and hosts the complete application framework of Android. It forks Java Virtual Machines (for every app) in which Dalvik EXecutable (`.dex`) code runs which is neither 32-bit nor 64-bit. But the JVMs are native processes; either 32 or 64-bit depending on the JNI libraries the app contains.

We can run 32-bit OS on 64-bit device if 64-bit:

1. Processor supports running 32-bit code which is usually the case because backward compatibility is desired, but not always.

2. Kernel supports running 32-bit code because unlike bare-metal hypervisors we - the processes on Android - don't deal directly with hardware.

PROCESSOR'S BITNESS
---
Every 64-bit processor's support for 32-bit execution isn't universal. For instance Samsumg Exynos 9 Series 982x SoCs contain [Cortex-A55][1] and A75 which (are based on ARMv8.x and they) have support for `aarch64` and `aarch32`. On the other hand Qualcomm's [Centriq 2400][2] SoCs and Cavium's [Thunder X2][3] SoCs also include ARMv8.x processors but without `aarch32` support.

In order to find device architecture, we can read `/proc/cpuinfo` which [exposes][4] information from [Main ID register][5] of the processor.
```
~$ cat /proc/cpuinfo
...
CPU implementer : 0x41
CPU architecture: 8
...
CPU part        : 0xd03
...
Hardware        : Qualcomm Technologies, Inc MSM8953
```
But there in no direct information like [`lm`][6] flag to confirm 32/64-bit support. So we need to get technical details of hardware. As per the [requirements][7] from Google, `CPU architecture: 8` indicates that it's a `ARMv8` device. Also see [this commit][8]. And [here][9] is the hex to human readable decoding map which `lscpu` command uses.
```
~$ lscpu | grep -E 'Vendor |Model '
Vendor ID:           ARM
Model name:          Cortex-A53
```
Other possible ways to get SoC information:
```
~$ cat /sys/firmware/devicetree/base/model
Qualcomm Technologies, Inc. MSM8953 + PMI8950 QRD SKU3
```
```
~$ cat /sys/devices/soc0/{vendor,family,machine}
Qualcomm
Snapdragon
MSM8953
```
It's evident from technical specifications of Qualcomm Snapdragon 625 ([MSM 8953][10]) and [Cortex-53][11] that it's based on ARMv8 architecture, which can process both instruction sets: `aarch64` and `aarch32`.

KERNEL'S BITNESS
---
When `arm64` support was [added][12] to Linux kernel, 32-bit compatibility mode was also included. If kernel is built with `IKCONFIG_PROC`, confirm by:
```
~# zcat /proc/config.gz | grep -E 'CONFIG_ARM64=|CONFIG_COMPAT=|BINFMT'
CONFIG_ARM64=y
CONFIG_COMPAT=y
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_BINFMT_SCRIPT=y
```
So the 64-bit ELF files are executed natively with [binfmt_elf][13] while 32-bit ELF files are executed with [compat_binfmt_elf][14]. See details in [this answer][15].

Usually `uname -m` is used to find the architecture of device supported by kernel. It shows the persoanlity ([execution domain][16]) of the process which defaults to kernel's primary architecture (`PER_LINUX` ). But Linux kernel supports changing [*persoanlity*][17], so this approach can be confusing:
```
~$ uname -m
aarch64
~$ setarch linux32 uname -m
armv8l
```
In latter command `uname` is running under 32-bit [compatible personality][18]. The same would happen if you use some app - like [this][19] - which [runs][20] with `LINUX32` personality, no matter even if kernel and `uname` binaries are 64-bit. For details see [this][21] and [this][22]. `lscpu` also confirms CPU operation modes using same phenomenon.

USERCODE BITNESS
---
Now coming to the userspace, `init` is the very first process run by kernel. Lets check its bitness. If the 5th byte is 1 it's 32-bit ELF file, if it's 2 the binary is 64-bit:
```
~# hexdump -n5 /proc/1/exe
0000000 457f 464c 0002
```
Or use `file` command:
```
~# file /proc/1/exe
/proc/1/exe: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked ...
```

Similarly check bitness of other vital OS binaries/libraries:
```
~$ file /system/lib*/libc.so
/system/lib/libc.so:   ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked ...
/system/lib64/libc.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked ...
```
```
~$ file /system/bin/linker*
/system/bin/linker:        ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked ...
/system/bin/linker64:      ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked ...
```
OS maintains 64-bit as well as 32-bit libraries and dynamic linker because apps may contain both types of binary code (though the major part must be Java/Dalvik bytecode). For instance the `dnsmasq` program which serves as DHCP server on hotspot is a 64 bit binary while Google Play Services uses a 32-bit library:
```
~# readelf -a /system/bin/dnsmasq
  Class:                             ELF64
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
      [Requesting program interpreter: /system/bin/linker64]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
```
```
~# readelf -a /data/data/com.google.android.gms/app_vision/ocr/libs/armeabi-v7a/libocr.so
  Class:                             ELF32
  Type:                              DYN (Shared object file)
  Machine:                           ARM
      [Requesting program interpreter: /system/bin/linker]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
```
Similarly it's not uncommon to have 32-bit binary blobs from OEMs / SoC vendors on 64-bit ROMs. Even some basic components of AOSP aren't 64-bit supported. Take example of [`audioserver`][23].  
To see all processes running in 32-bit mode:
```
~# for p in $(ps -p 2 --ppid 2 --deselect -o pid=); do grep -qE '^.{8}[^-]' /proc/$p/maps || echo $p; done | xargs ps f -o pid,cmd -p
  PID CMD
 3359 /system/bin/mediaserver
 3358 /system/bin/cameraserver
 3357 /system/bin/audioserver
 3356 zygote
 5081  \_ webview_zygote
20824  |   \_ com.android.webview:sandboxed_process0
18609  \_ it.colucciweb.vpnclient
 3354 /vendor/bin/hw/[email protected]
 2665 /vendor/bin/hw/[email protected]
 2335 /vendor/bin/mm-qcamera-daemon
 2278 /vendor/bin/wifidisplayhalservice
 2277 media.codec hw/[email protected]
 2244 /system/bin/drmserver
  777 /vendor/bin/hw/[email protected]
  773 /vendor/bin/hw/[email protected]
```
Out of these only one is a VPN app, rest are OS processes.

CONCLUSION
---
So it's clear that even if core OS is 64-bit, there are possibly large number of processes running as 32-bit, though each process and its linked libraries have to be be homogeneous; either 32 or 64-bit. And there's no constraint if the OS doesn't include 64-bit code at all, but you won't find many instances because OEMs ship 64-bit devices with 64-bit binary code. It's more about business than performance; that's what a user pays for. However exceptions do exist where business isn't that much involved: [Raspberry Pi 3 has 64-bit CPU, but 32-bit Raspbian OS][24]. Android phones examples from past include Galaxy E5, LG G Stylo, Moto G5 Plus, Lenovo A6000 Plus and MT6735 devices. But now Android is [moving][26] towards 64-bit and some devices may [drop][27] 32-bit support gradually.

>Does the same case happens for Android? Is there a 32-bit and a 64-bit version for the same 64-bit device?

Yes, take example of [Moto G4 Plus][25].

---

**RELATED:** [Android apps for “armeabi-v7a” and “x86” architecture: SoC vs. Processor vs. ABI][28]


  [1]: https://developer.arm.com/ip-products/processors/cortex-a/cortex-a55
  [2]: https://www.anandtech.com/show/11737/analyzing-falkors-microarchitecture-a-deep-dive-into-qualcomms-centriq-2400-for-windows-server-and-linux
  [3]: https://en.wikichip.org/wiki/cavium/thunderx2
  [4]: https://community.arm.com/developer/tools-software/oss-platforms/w/docs/245/cpufreq-dvfs
  [5]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/CIHFAACD.html
  [6]: https://en.wikipedia.org/wiki/CPUID#EAX.3D80000001h:_Extended_Processor_Info_and_Feature_Bits
  [7]: https://source.android.com/compatibility/10/android-10-cdd#3_3_2_32-bit_arm_native_code_compatibility
  [8]: https://android.googlesource.com/kernel/common/+/93f22300975017f18c286899e8b98b5d843fe118
  [9]: https://github.com/karelzak/util-linux/blob/master/sys-utils/lscpu-arm.c
  [10]: https://www.qualcomm.com/products/snapdragon-625-mobile-platform
  [11]: https://developer.arm.com/products/processors/cortex-a/cortex-a53
  [12]: https://github.com/torvalds/linux/commit/8c2c3df31e3b87cb5348e48776c366ebd1dc5a7a
  [13]: https://github.com/torvalds/linux/blob/master/fs/Kconfig.binfmt#L5
  [14]: https://github.com/torvalds/linux/blob/master/fs/compat_binfmt_elf.c#L3
  [15]: https://stackoverflow.com/a/23295968/9165920).
  [16]: https://www.halolinux.us/kernel-reference/execution-domains.html
  [17]: http://man7.org/linux/man-pages/man2/personality.2.html
  [18]: https://android.googlesource.com/kernel/common/+/refs/heads/android-4.19/arch/arm64/include/asm/compat.h#32
  [19]: https://play.google.com/store/apps/details?id=jackpal.androidterm
  [20]: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-9.0.0_r47/core/java/android/content/pm/ApplicationInfo.java#870
  [21]: https://stackoverflow.com/a/45125525/9165920
  [22]: https://en.m.wikipedia.org/wiki/Uname#Examples
  [23]: https://www.mail-archive.com/[email protected]/msg20926.html
  [24]: http://linuxgizmos.com/raspberry-pi-3-has-a-64-bit-cpu-but-a-32-bit-raspbian-os
  [25]: https://www.xda-developers.com/moto-g4-plus-64-bit-custom-roms/
  [26]: https://developer.android.com/distribute/best-practices/develop/64-bit
  [27]: https://android.googlesource.com/platform/build/+/1ac8a6df9a8ad749e40c5a0f21cd75906a3bcff9
  [28]: https://android.stackexchange.com/a/208132/218526