One way to think about it is that the 8080 and derivatives have a 17-bit address bus rather than the normally cited 16-bit bus. The top bit of that address bus is the chip's input/output request line (IORQ).
When you use the normal loads and stores the top bit is always reset. When you perform an in or out the top bit is always set.
Intel named the line and expected it to be used for communicating with peripheral chips, hence the name, the much more limited form of available addressing, the extended costs of access and the fact that neither the program counter nor the stack pointer can point into that area of address space.
That leaves Intel with the problem that they've got 16 bits of address bus to fill but have taken only an 8-bit parameter. What they actually do is they load the accumulator into the top 8 bits. So if you had:
LD A, 0xfe
OUT (0xdc)
Then the value 0xfe would be output to the port address 0xfedc.
(aside: apologies for the Zilog syntax rather than Intel; possibly interestingly the Z80 adds a bunch of instructions like OUT (C), A
that really dump the entirety of BC onto the address bus rather than merely C and most Z80 micro manufacturers were perfectly happy to use the full 16-bit address as it allowed them to use the simplified logic of 'component is being addressed if this address line is low' while still having a decent range left over for external peripherals)