Decoupling setting of specific bits (transfer mode, stream, channel) from the generic DMA_Init() function
An init() function should contain everything that you need to tell the driver before it starts operation. As for making a portable, abstract API for DMA, it's quite unlikely that you'll manage to create a meaningful one, since it is so very MCU-specific.

That being said, you can solve this in classic C along the lines of this:

// dma.h
dma_err_t dma_init (const void* settings);


Then implement this in a STM32-specific module:

// stm32_dma.h

#include "dma.h"

typedef struct
{
  /* stuff */
} stm32_dma_settings_t;


And then implement it accordingly:

// stm32_dma.c

#include "stm32_dmh.h"

dma_err_t dma_init (const void* settings)
{
  const stm32_dma_settings_t* stm32_settings = settings;
  ...
}


This allows you to leave out hardware-specific details from the API. The dma_start function can be written in the same manner, so that it takes a specific struct as parameter.